QScriptEngineAgent - retrieving the name of the caller

I am trying to create a basic performance profiler for QtScript using the QScriptEngineAgent in order to capture function entries and exits. I have successfully set up the callback for

QScriptEngineAgent::functionEntry()
. My question is, can I retrieve the name of the function being called as a string within this callback?

Although I understand that not all script functions necessarily have names, even in simple cases it doesn't seem to be working. Despite attempts with QScriptContextInfo, it does not provide the function name. Trying to access arguments.callee.name also failed.

Below is an outline of my implementation attempts, which I am testing on qt-5.3.2/linux.

tmp.pro:

TEMPLATE = app
TARGET = tmp
INCLUDEPATH += .
QT += core script
SOURCES += main.cpp

main.cpp:

#include <QCoreApplication>
#include <QScriptEngine>
#include <QScriptEngineAgent>
#include <QScriptContextInfo>
#include <QDebug>

class MyAgent: public QScriptEngineAgent {
private:
    void functionEntry(qint64 scriptId) {
        qDebug() << "functionEntry" << scriptId;
        QScriptContext *context = engine()->currentContext();

        // Attempting to retrieve the function name from context info
        QScriptContextInfo contextInfo(context);
        qDebug() << contextInfo.functionName();

        // Trying to access the function name through arguments.callee.name
        QScriptValue callee = context->callee();
        qDebug() << callee.property("name").toString();

        // Checking if function.toString() provides any useful information
        qDebug() << callee.toString();

        // Printing out details of the current context
        qDebug() << context->toString();
    }
public:
    MyAgent(QScriptEngine *eng) : QScriptEngineAgent(eng) {
        qDebug() << "engine" << eng;
    }
};

int main(int argc, char **argv) {
    QCoreApplication app(argc, argv);
    QScriptEngine eng;
    MyAgent agent(&eng);
    eng.setAgent(&agent);
    qDebug() << "agent " << eng.agent();
    eng.evaluate("function foo() { return 6 * 7; }"
                 "function bar() { return foo(); }");
    QScriptValue bar = eng.globalObject().property("bar");

    // Confirming that callee is printed correctly here
    qDebug() << "call " << bar.property("name").toString() << bar.toString();
    QScriptValue ret = bar.call();
    qDebug() << "answer" << ret.toNumber();
    return 0;
}

This is a sample of the output, which does not meet my expectations as I would like to see "foo" and "bar" instead of empty strings:

engine QScriptEngine(0x7fffc55c4560)
agent  0x7fffc55c4570
functionEntry 140300485581200
""
""
""
"<global>() at -1"
functionEntry -1
""
""
""
"<global>() at -1"
call  "bar" "function bar() { return foo(); }"
functionEntry 140300485581200
""
""
""
"<global>() at -1"
functionEntry 140300485581200
""
""
""
"<global>() at -1"
answer 42

Answer №1

It appears that the correct context is only accessible in positionChange. Fortunately, functionEntry is triggered with a scriptID greater than 0 whenever a true context change occurs. Retrieving the context in the subsequent positionChange sequence works well for me:

class ScriptProfilerAgent: public QScriptEngineAgent
{
public:
    ScriptProfilerAgent(QScriptEngine *eng)
        : QScriptEngineAgent(eng), m_stackChange(false)
    {
    }

protected:
    void scriptLoad(qint64 id, const QString &program, const QString &fileName, int baseLineNumber)
    {
        Q_UNUSED(id);Q_UNUSED(program);Q_UNUSED(fileName);Q_UNUSED(baseLineNumber);
        m_timer.start();
    }

    void functionEntry(qint64 scriptId)
    {
        if (scriptId > -1) {
            // prepare for stack tracking => positionChange
            m_stackChange = true;
        }
    }

    void positionChange(qint64 scriptId, int lineNumber, int columnNumber)
    {
        Q_UNUSED(scriptId);Q_UNUSED(lineNumber);Q_UNUSED(columnNumber);
        if (m_stackChange)
        {
            QString fn = functionNameEx();
            m_curCallStack.push(qMakePair(fn,m_timer.elapsed()));
            // reset stack tracking
            m_stackChange = false;
        }
    }

    // More code here...

In order to utilize the agent, simply assign it to the engine using

engine.setAgent(new ScriptProfilerAgent());
. Upon completion, the profiler can provide you with a list of function and stack path names along with total execution times and call counts:

QString ScriptEngine::getProfilingResults()
{
    ScriptProfilerAgent* spa = dynamic_cast<ScriptProfilerAgent*>(agent());
    if (spa)
    {
        QString result = spa->toString();
        spa->reset();
        return result;
    }
    return "<no profiler agent>";
}

FN-Path Total Time (ms) Calls
global  235969ms    7
global>anonymous    0ms 38
global>run  235969ms    1
global>run>doConcept    206444ms    21603
global>run>doConcept>genData    200765ms    21603
global>run>...    

Thank you,

Johannes

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

AngularJS - Issues with Firebase resetPassword not showing updated changes

When incorrect email addresses are entered and the form is submitted, the error message does not display for the user. However, if additional characters are appended to the existing entries, the message appears on the screen. In debugging, the variable $sc ...

Tips for merging values from a json file with a geojson map file

I have a task at hand where I am aiming to merge a GeoJSON map file with pertinent key values from a JSON file in order to create a choropleth map. Let's take a look at the structure of these files: data1.json { "type": "FeatureCollection", ...

When using ng-repeat in Angular.js, an additional td is created

https://jsfiddle.net/gdrkftwm/ https://i.sstatic.net/CTi2F.jpg I have encountered a problem while creating a table from a Json object. There seems to be an extra td being generated, and I'm not sure why. I want the structure of my table to resemble ...

Load a 3D object or model using three.js and then make modifications to its individual components

Seeking advice on displaying and manipulating a 3D model of a robot arm in a browser. How can I load the model into three.js to manipulate all the sub-parts of the robot arm? Using Inventor, I have an assembly of a rotary motor and a shaft exported as an ...

You may encounter the error MSB8020 stating that the build tools for v141 (Platform Toolset = 'v141') cannot be located while attempting to install the npm module scrypt

I am currently attempting to install the npm module scrypt onto my system. After conducting some research, I found out that scrypt requires node-gyp for installation. Despite installing node-gyp globally multiple times, I continue to encounter issues. Add ...

Explore the search bar with functional filtering for JSON items

I'm currently working on creating a dynamic filter bar integrated with a search functionality. My data is stored in JSON format, including details such as artist name, title, source, and more. Despite successfully retrieving results through console.lo ...

Merging Two Angular Pages within a Jhipster Application

My jhipster application is simple, generating 2 entities: Product and Category. The generated pages to list the data for these entities can be found here. Specifically, there are pages for Product and Category. If I want to create a new page that combines ...

javascript search for parent function argument

I am struggling to figure out how to locate the key in my json array. When I try to find the key using a function parameter, it does not seem to work. This is a snippet of my json data: ... { "product": [ { "title": " ...

Creating a line graph with d3.js

I am currently working on implementing a line chart using data in JSON format following the steps outlined in this tutorial: [{"Machine":"S2","Data":[{"Percentage":0,"Week":33,"Year":2014,"Monday":"11/08/14","Items":0},{"Percentage":0,"Week":34,"Year":201 ...

Docker: CORS policy is blocking access to XMLHttpRequest

After creating an ASP.NET Web Application (.NET Framework) project in Visual Studio 2022 and adding a web service to it, everything seemed to work fine when testing the web service call on Local IIS. However, things took a different turn when I tried runni ...

Setting a default currency value (either in dollars or euros) in an input field

Is there a way to automatically insert a currency symbol (€, $) in a text field by default when entering a number? Are there any default values for this feature? Thank you Here is an example ...

Insert some text into the div element. Create a new line

I'm looking to make a specific text on my webpage trigger a new line when displayed in a div. I've been struggling to figure out how to accomplish this: var original= "the text @n to change"; var changed = original.replace(/@n /g, '\ ...

unable to send array in cookie through express isn't functioning

Currently, I am in the midst of a project that requires me to provide the user with an array. To achieve this, I have been attempting to utilize the res.cookie() function. However, each time I try to pass an array as cookie data, the browser interprets it ...

Most effective method for eliminating an item from an array with AngularJs

I have an array of objects that I want to modify by removing multiple objects from it. The following code is currently achieving this successfully, but I'm curious to know if there is a more efficient way to accomplish this task. This process involv ...

Enable users to upload and run JavaScript code on the server

Currently, I am diving into the world of javascript/nodeJS with the goal of creating an ERP solution. My aim is to give ERP end-users the ability to upload their own customized scripts which can then interact with existing ERP scripts. It goes without sayi ...

Using Express.js to transform req.body into a POST encoded string

I need to convert the req.body object into a POST encoded string using the express.bodyParser middleware. Is there a way to achieve this? For example: Name: Jane Doe Age: 30 City: Los Angeles Should become: Name=Jane+Doe&Age=30&City=Los+Angeles ...

Mastering advanced String templating using loops and control statements in Javascript

During runtime, I receive an array similar to the example below: var colors = ['red', 'green', 'blue']; I then need to create a JSON String that looks like this: { "color" : { "name" : "foo", "properties ...

The ngIf statement in the template isn't functioning properly after a refresh; instead, it is causing a redirection to the homepage

I've been developing with Angular 7, trying to display a <div> ... </div> based on multiple values that I declared as : Boolean = false; in the .ts file. These values are updated in ngOnInit, but for some reason, the page keeps redirecting ...

"Crafting QML applications that can adapt to any screen

How can I achieve consistent sizing for text, buttons, margins, and decorative elements across different platforms in Qt/QML? I am looking for a resolution independent measurement unit that can make the size uniform on desktop (retina and non-retina), and ...

When a button is pressed, a QWidget does not activate the QEvent::MouseMove event when entered

Using Qt and C++, I have successfully created a window with a small QWidget embedded inside. This small QWidget is programmed to display a message whenever a QEvent::Enter, QEvent::Leave, or QEvent::MouseMove event occurs. However, I noticed that when a ...