Function names in CpuProfileNode.

51 views
Skip to first unread message

Jane Chen

unread,
Oct 29, 2015, 6:46:21 PM10/29/15
to v8-users
Testing profiling against v8 4.6.88.

I have functions that are exposed through accessor callbacks.  If a native function is set for multiple accessor properties, the last property shows up as the function name in the CpuProfileNode, regardless what name you set to the function returned by the accessor function.  For example:

global->SetAccessor(
    v8::String::NewFromUtf8(isolate, "print", v8::NewStringType::kNormal)
          .ToLocalChecked(),
    getFunction);
global->SetAccessor(
    v8::String::NewFromUtf8(isolate, "read", v8::NewStringType::kNormal)
          .ToLocalChecked(),
    getFunction);

Now "get read" is the function name in CpuProfileNode although print is called.

Test script:
 
function isPrime(num) {
  for (var count = 2; count < num; count++)
    if (num % count == 0) return false;
  return true;
};
 
var total = 0;
for (var i = 2; i < 100000; i++) {
  if (isPrime(i)) {
    print(i);
    total++
  }
};
total;
 
TotalHitCount:2233

FunctionName:(root)
LineNumber:0
ColumnNumber:0
HitCount:0
    FunctionName:(program)
    LineNumber:0
    ColumnNumber:0
    HitCount:7
    FunctionName:
    LineNumber:0
    ColumnNumber:0
    HitCount:13
        FunctionName:isPrime
        LineNumber:1
        ColumnNumber:17
        HitCount:8
    FunctionName:
    LineNumber:1
    ColumnNumber:1
    HitCount:2196
        FunctionName:get read
        LineNumber:0
        ColumnNumber:0
        HitCount:2
    FunctionName:(garbage collector)
    LineNumber:0
    ColumnNumber:0
    HitCount:7


Given that an accessor callback takes a property name, it should allow one native function to handle multiple properties.  Is this a bug, or am I doing something wrong? 

Jane Chen

unread,
Oct 29, 2015, 6:57:04 PM10/29/15
to v8-users
A test case to demonstrate the issue can be found at:

https://code.google.com/p/v8/issues/detail?id=4527

Jakob Kummerow

unread,
Oct 30, 2015, 5:12:12 AM10/30/15
to v8-users
Well, the profile tells you which function was executed. It doesn't know or care what name you used to refer to this function -- it can't, as it's a sampling profiler. Pure-JS example:

function f() { /* long-running stuff */ }
var g = f;
g();  // Shows up as "f" in the profile.

In your example, the function is a C++ object, so it doesn't even have a name, so V8 tries to infer a name that it hopes is meaningful to a human reader. The point is that for a single function, it can only infer a single name.

I think this is working as intended.

--
--
v8-users mailing list
v8-u...@googlegroups.com
http://groups.google.com/group/v8-users
---
You received this message because you are subscribed to the Google Groups "v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to v8-users+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Jane Chen

unread,
Oct 30, 2015, 6:03:27 PM10/30/15
to v8-users
Is there anyway to use something like CreateDataProperty to override the accessor so that the actual function is associated with the property, albeit lazily created?

I tried to use CreateDataProperty in place of ForceSet, since ForceSet is deprecated, but that didn't do it, and my property becomes undefined.

Alex Kodat

unread,
Oct 31, 2015, 1:04:24 PM10/31/15
to v8-users
CreateDataProperty or DefineOwnProperty should work. Of course, you have to make sure that the first time the function is accessed via the accessor when you do your override, you have to return the function from the accessor. But I assume you're doing that?

Jane Chen

unread,
Oct 31, 2015, 2:03:10 PM10/31/15
to v8-users
Yes, the first time the property is accessed, it gets the correct native function.  In my accessor before I return, I have:

    global->SetAccessor(context,property,0);
    global->CreateDataProperty(context,property,obj);

Then the property becomes undefined the second time on.

Alex Kodat

unread,
Oct 31, 2015, 6:56:50 PM10/31/15
to v8-users
Sorry, you're right -- I should have researched the history and behavior of CreateDataProperty and DefineOwnProperty. And, in fact, it does appear that they will not replace an exisiting object property. Given that, it seems like you have no choice other than to use ForceSet (until CreateDataProperty and DefineOwnProperty are fixed?).

While I guess ForceSet was a little uncool in that it allowed replacing even non-configurable (v8::DontDelete) properties, IMO CreateDataProperty and DefineOwnProperty seem to go too far in the other direction.

Just out of curiosity, were your examples of read and print used for simplicity or are these really the functions you're lazily instantiating? If the latter, is an accessor really that much cheaper to set up then just adding the function right away as an object property? I can definitely see using lazy instantiation for a function if it's a constructor and comes along with a bunch of other stuff but if it's just a simple function, I would think the FunctionTemplate::New()->GetFunction() isn't going to be noticably slower than SetAccessor. Of course, you might be doing tricky stuff like dynamically loading the functions or maybe compiling JavaScript callbacks with your function or whatever, in which case lazy instantiation would make perfect sense. 

Jane Chen

unread,
Oct 31, 2015, 7:11:22 PM10/31/15
to v8-users
ForceSet worked in 3.24.  It is not working in 4.6.88.  So I do not have a way to override an accessor once it is set.

I am showing read and print for simplicity to demonstrate the issue using v8 shell.cc.  In my embedding app, before using accessors, creating a context used to take ~2.9ms; after, ~0.5ms.  Measured against 3.24.

On Saturday, October 31, 2015 at 3:56:50 PM UTC-7, Alex Kodat wrote

Jane Chen

unread,
Oct 31, 2015, 7:17:08 PM10/31/15
to v8-users
I'm not doing anything fancy like dynamically loading or compiling.  Purely for performance sake.  See this:

Alex Kodat

unread,
Oct 31, 2015, 7:37:13 PM10/31/15
to v8-users
FWIW, ForceSet seems to work for me for the exact same purpose you're using it for. I'm running 4.8.194 at the moment and I traced my accessor for a constructor that I then replaced with the actual constructor using ForceSet and the accessor was only entered once for the constructor property reference. Replacing the ForceSet with CreateDataProperty or DefineOwnProperty produced behavior similar to what you're seeing -- my accessor was entered repeatedly.

Is ForceSet just silently failing for you? Is it returning false?

Jane Chen

unread,
Oct 31, 2015, 8:18:26 PM10/31/15
to v8-users
Okay, you were right.  I don't know what I was missing.  But ForceSet does work as before.  Tested against 4.7.0.

However, with ForceSet and setting the accessor to 0, the last property name associated with the accessor callback still shows up in the profile for the function being ForceSet to global!  I still need a solution for my profiling support!

Anyway this is helpful and I'll put ForceSet back.  Thanks!
Reply all
Reply to author
Forward
0 new messages