Hi all!

There are 3 tests detailed in this mail:
1. ExternalResource garbage collector performance
2. Isolate/Context performance comparisons
3. Isolate/Context memory usage comparisons

1. ExternalResource garbage collector performance:
I messed up the ExternalResource test I had sent to Jędrek before so here is a new test case (external-resource-tester.cpp). I used a helper class for measuring which I also attached to this mail (tester.h, tester.cpp). A sample run with 100 test cases:

Mean of ExternalResource      : 22.34 ms.
Deviation of ExternalResource : 0.19 ms.
Number of Point objects       : 0.
Mean of MakeWeak              : 33.82 ms.
Deviation of MakeWeak         : 0.32 ms.
Number of Point objects       : 0.

2. Isolate/Context memory usage comparisons:
We used a Valgrind tool called Freya (see http://webkit.sed.hu/node/29) to measure the memory consumption of the test cases.
The test cases use greatly simplified Engine-like classes as follows:
  - Using an own Context and the default Isolate (context-memtest.cpp)
  - Using an own Context and an own Isolate (isolate-memtest.cpp)
  - Using an own Isolate and no Context at all (pure-isolate-memtest.cpp)
We tested each cases with 1, 5, 10 and 15 instances of test objects.
The results are:
  - context-memtest 1: 984.0Kb, 5: 1.7Mb, 10: 2.5Mb, 15: 2.9Mb
  - isolate-memtest 1: 1.4Mb, 5: 4.1Mb, 10: 7.6Mb, 15: 11.1Mb
  - pure-isolate-memtest 1: 796.0Kb, 5: 788.0Kb, 10: 792.0Kb, 15: 792.0Kb

3. Isolate/Context performance comparisons:
These tests are also use simplified Engine-like classes as the ones in the memory benchmarks and the same Tester class as the ExternalResource test (isolate-context-tester.cpp, tester.h, tester.cpp). A sample run with 100 test cases:

Mean:
Own Isolate     : 34.86 ms
Default Isolate : 5.47 ms
Pure Isolate    : 30.26 ms
Deviation:
Own Isolate     : 0.21 ms
Default Isolate : 0.02 ms
Pure Isolate    : 0.18 ms

Best regards:
Szeged Team

----------------------------------------------------------------
This message was sent using IMP, the Internet Messaging Program.

/*
 * Benchmark - ExternalResource
 * Usage: external-resource-tester [number_of_tests]
 * 
 */

#include <v8.h>
#include <cstdlib>
#include "tester.h"


using namespace v8;
using namespace std;


class Point {
public:
    static int counter;

    Point(int x, int y) : x_(x), y_(y)
    {
        ++counter;
    }

    ~Point()
    {
        --counter;
    }

    int x_;
    int y_;
};

int Point::counter = 0;


class V8ObjectResource : public v8::Object::ExternalResource {
public:
    V8ObjectResource() {}
    enum ResourceType { POINT_TYPE, SOME_OTHER_TYPE };
    virtual ResourceType getResourceType() const = 0;
};


class V8PointResource : public V8ObjectResource {
public:
    V8PointResource(Point* p) : point(p) {}
    ~V8PointResource()
    {
        delete point;
    }
    
    enum { V8_RESOURCE_TYPE = V8ObjectResource::POINT_TYPE };
    
    V8ObjectResource::ResourceType getResourceType() const
    {
        return V8ObjectResource::POINT_TYPE;
    }

private:
    Point* point;
};


template <class T>
inline T* v8_resource_cast(Handle<Object> object)
{
    V8ObjectResource* resource = static_cast<V8ObjectResource*>(object->GetExternalResource());
    return (resource && 
            (uint32_t)resource->getResourceType() == (uint32_t)T::V8_RESOURCE_TYPE) ? static_cast<T*>(resource) : 0;
}


void weakPointCallback(Persistent<Value> object, void* parameter)
{
    Point* point = static_cast<Point*>(parameter);
    delete point;
    object.Dispose();
    object.Clear();
}


void MeasureExternalResource(int counter, Tester* tester)
{
    v8::Handle<v8::ObjectTemplate> point_templ = v8::ObjectTemplate::New();
    point_templ->SetHasExternalResource(true);
    Point* p;
    V8PointResource* point_resource;

    {
        HandleScope inner_scope;
        Persistent<Object> obj;
        for (int i = 0; i < counter; ++i) {
            p = new Point(i, i + 1);
            point_resource = new V8PointResource(p);
            obj = Persistent<Object>::New(point_templ->NewInstance());
            obj->SetExternalResource(point_resource);
            obj.Dispose();
        }
    }

    tester->startMeasuring();
    while (!V8::IdleNotification()) { }
    tester->endMeasuring();
}


void MeasureMakeWeak(int counter, Tester* tester)
{
    v8::Handle<v8::ObjectTemplate> point_templ = v8::ObjectTemplate::New();
    point_templ->SetInternalFieldCount(1);
    Persistent<Object> obj;
    Point* point;

    {
        HandleScope embedded_scope;
        for (int i = 0; i < counter; ++i) {
            point = new Point(i, i + 1);
            obj = Persistent<Object>::New(point_templ->NewInstance());
            obj->SetInternalField(0, External::New(point));
            obj.MakeWeak(point, weakPointCallback);
        }
    }

    tester->startMeasuring();
    while (!V8::IdleNotification()) { }
    tester->endMeasuring();
}


int main(int argc, char* argv[])
{
    if (argc > 2) {
        return 666;
    }

    int number_of_tests = 1;
    if (argc == 2) {
        int num = atoi(argv[1]);
        if (num) {
            number_of_tests = num;
        } else {
            return 666;
        }
    }

    HandleScope handle_scope;
    
    v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();

    Persistent<Context> context = Context::New(NULL, global);
    Context::Scope context_scope(context);

    const int OBJECT_COUNTER = 100000;

    Tester* externalTester = new Tester();
    Tester* weakTester = new Tester();

    for (int i = 0; i < number_of_tests; ++i) {
        MeasureExternalResource(OBJECT_COUNTER, externalTester);
        MeasureMakeWeak(OBJECT_COUNTER, weakTester);
    }

    printf("Mean of ExternalResource      : %.2lf ms.\n", externalTester->getMean());
    printf("Deviation of ExternalResource : %.2lf ms.\n", externalTester->getDeviation());
    printf("Number of Point objects       : %d.\n", Point::counter);

    printf("Mean of MakeWeak              : %.2lf ms.\n", weakTester->getMean());
    printf("Deviation of MakeWeak         : %.2lf ms.\n", weakTester->getDeviation());
    printf("Number of Point objects       : %d.\n", Point::counter);
    
    context.Dispose();

    return 0;
}



#ifndef TESTER_H
#define TESTER_H


#include <vector>
#include <iterator>
#include <sys/time.h>
using namespace std;


class Tester {
public:
    Tester();
    ~Tester();
    void startMeasuring();
    void endMeasuring();
    int getNumberOfTests() const;
    double getMean() const;
    double getVariance() const;
    double getDeviation() const;
    double getLastResult() const;

    typedef vector<double>::const_iterator tester_iterator;
    tester_iterator begin();
    tester_iterator end();
    void clear();

private:
    double getTimeDiff();

    Tester(const Tester&);
    Tester& operator=(const Tester&);

    vector<double>* m_results;
    struct timeval m_start;
    struct timeval m_end;
    double m_startTime;
    double m_endTime;
};


#endif
#include "tester.h"
#include <cmath>


Tester::Tester()
{
    m_results = new vector<double>();
}


Tester::~Tester()
{
    delete m_results;
}


void Tester::startMeasuring()
{
    gettimeofday(&m_start, NULL);
}


void Tester::endMeasuring()
{
    gettimeofday(&m_end, NULL);
    m_results->push_back(getTimeDiff());
}


double Tester::getLastResult() const
{
    return m_results->back();
}


int Tester::getNumberOfTests() const
{
    return m_results->size();
}


double Tester::getMean() const
{
    double sum = 0;
    for (vector<double>::iterator it = m_results->begin();
            it != m_results->end(); ++it) {
        sum += *it;
    }
    return sum / m_results->size();
}


double Tester::getVariance() const
{
    double variance_numerator = 0;
    for (vector<double>::iterator it = m_results->begin();
            it != m_results->end(); ++it) {
        variance_numerator += pow(*it - getMean(), 2);
    }
    return variance_numerator / m_results->size();
}


double Tester::getDeviation() const
{
    return sqrt(getVariance());
}


Tester::tester_iterator Tester::begin()
{
    return m_results->begin();
}


Tester::tester_iterator Tester::end()
{
    return m_results->end();
}


void Tester::clear()
{
    m_results->clear();
}


double Tester::getTimeDiff()
{
    m_startTime = m_start.tv_sec * 1000000 + m_start.tv_usec;
    m_endTime = m_end.tv_sec * 1000000 + m_end.tv_usec;    
    return (m_endTime - m_startTime) / 1000;
}

/*
 * Benchmark - Isolate/Context performance
 * Usage: isolate-context-benchmark [number_of_tests]
 */

#include <v8.h>
#include <cstdlib>
#include "tester.h"


using namespace v8;
using namespace std;


class EngineWithPureIsolate {
public:
    EngineWithPureIsolate()
    {
        m_isolate = Isolate::New();
    }

    ~EngineWithPureIsolate()
    {
        m_isolate->Dispose();
    }

    void doStuff()
    {
        m_isolate->Enter();
        m_isolate->Exit();
    }
private:
    Isolate* m_isolate;
};


class EngineWithOwnIsolate {
public:
    EngineWithOwnIsolate()
    {
        m_isolate = Isolate::New();
        m_isolate->Enter();
        m_context = Context::New();
        m_isolate->Exit();
    }

    ~EngineWithOwnIsolate()
    {
        m_isolate->Enter();
        m_context.Dispose();
        m_isolate->Exit();
        m_isolate->Dispose();
    }

    void doStuff()
    {
        m_isolate->Enter();
        m_context->Enter();

        m_context->Exit();
        m_isolate->Exit();
    }

private:
    EngineWithOwnIsolate(const EngineWithOwnIsolate&);
    EngineWithOwnIsolate& operator=(const EngineWithOwnIsolate&);

    Isolate* m_isolate;
    Persistent<Context> m_context;
};


class EngineWithDefaultIsolate {
public:
    EngineWithDefaultIsolate()
    {
        m_context = Context::New();
    }
    
    ~EngineWithDefaultIsolate()
    {
        m_context.Dispose();
    }

    void doStuff()
    {
        m_context->Enter();

        m_context->Exit();
    }

private:
    EngineWithDefaultIsolate(const EngineWithDefaultIsolate&);
    EngineWithDefaultIsolate& operator=(const EngineWithDefaultIsolate&);

    Persistent<Context> m_context;
};


int main(int argc, char* argv[])
{
    if (argc > 2) {
        return 666;
    }

    int number_of_tests = 1;
    if (argc == 2) {
        int num = atoi(argv[1]);
        if (num) {
            number_of_tests = num;
        } else {
            return 666;
        }
    }

    HandleScope scope;
    Persistent<Context> context = Context::New();
    Context::Scope context_scope(context);
    Handle<Value> result;

    const int NUMBER_OF_LOOPS = 100000;

    EngineWithOwnIsolate* engine_with_own_isolate = new EngineWithOwnIsolate();
    EngineWithDefaultIsolate* engine_with_default_isolate = new EngineWithDefaultIsolate();
    EngineWithPureIsolate* engine_with_pure_isolate = new EngineWithPureIsolate();

    Tester* ownIsolateTester = new Tester();
    for (int i = 0; i < number_of_tests; ++i) {
        ownIsolateTester->startMeasuring();
        for (int i = 0; i < NUMBER_OF_LOOPS; ++i) {
            engine_with_own_isolate->doStuff();
        }
        ownIsolateTester->endMeasuring();
    }

    Tester* defaultIsolateTester = new Tester();
    for (int i = 0; i < number_of_tests; ++i) {
        defaultIsolateTester->startMeasuring();
        for (int i = 0; i < NUMBER_OF_LOOPS; ++i) {
            engine_with_default_isolate->doStuff();
        }
        defaultIsolateTester->endMeasuring();
    }

    Tester* pureIsolateTester = new Tester();
    for (int i = 0; i < number_of_tests; ++i) {
        pureIsolateTester->startMeasuring();
        for (int i = 0; i < NUMBER_OF_LOOPS; ++i) {
            engine_with_pure_isolate->doStuff();
        }
        pureIsolateTester->endMeasuring();
    }

    printf("Mean:\n");
    printf("Own Isolate     : %.2lf ms\n", ownIsolateTester->getMean());
    printf("Default Isolate : %.2lf ms\n", defaultIsolateTester->getMean());
    printf("Pure Isolate    : %.2lf ms\n", pureIsolateTester->getMean());

    printf("Deviation:\n");
    printf("Own Isolate     : %.2lf ms\n", ownIsolateTester->getDeviation());
    printf("Default Isolate : %.2lf ms\n", defaultIsolateTester->getDeviation());
    printf("Pure Isolate    : %.2lf ms\n", pureIsolateTester->getDeviation());

    delete engine_with_own_isolate;
    delete engine_with_default_isolate;
    delete engine_with_pure_isolate;

    context.Dispose();

    return 0;
}



/*
 * Benchmark - Isolate/Context
 * Usage: context-memtest [number_of_engines]
 * 
 */

#include <v8.h>
#include <vector>
#include <cstdlib>


using namespace v8;
using namespace std;

class EngineWithDefaultIsolate {
public:
    EngineWithDefaultIsolate()
    {
        m_context = Context::New();
    }
    
    ~EngineWithDefaultIsolate()
    {
        m_context.Dispose();
    }

private:
    EngineWithDefaultIsolate(const EngineWithDefaultIsolate&);
    EngineWithDefaultIsolate& operator=(const EngineWithDefaultIsolate&);

    Persistent<Context> m_context;
};


int main(int argc, char* argv[])
{
    if (argc > 2) {
        return 666;
    }

    int number_of_engines = 1;
    if (argc == 2) {
        int num = atoi(argv[1]);
        if (num) {
            number_of_engines = num;
        } else {
            return 666;
        }
    }

    HandleScope scope;
    Persistent<Context> context = Context::New();
    Context::Scope context_scope(context);

    vector<EngineWithDefaultIsolate* >* engines = new vector<EngineWithDefaultIsolate* >();
    for (int i = 0; i < number_of_engines; ++i) {
        engines->push_back(new EngineWithDefaultIsolate());
    }

    for (vector<EngineWithDefaultIsolate*>::iterator it = engines->begin();
            it != engines->end();
            ++it) {
        delete *it;
    }

    delete engines;

    context.Dispose();
    return 0;
}



/*
 * Benchmark - Isolate/Context
 * Usage: isolate-memtest [number_of_engines]
 * 
 */

#include <v8.h>
#include <vector>
#include <cstdlib>


using namespace v8;
using namespace std;


class EngineWithOwnIsolate {
public:
    EngineWithOwnIsolate()
    {
        m_isolate = Isolate::New();
        m_isolate->Enter();
        m_context = Context::New();
        m_isolate->Exit();
    }

    ~EngineWithOwnIsolate()
    {
        m_isolate->Enter();
        m_context.Dispose();
        m_isolate->Exit();
        m_isolate->Dispose();
    }

private:
    EngineWithOwnIsolate(const EngineWithOwnIsolate&);
    EngineWithOwnIsolate& operator=(const EngineWithOwnIsolate&);

    Isolate* m_isolate;
    Persistent<Context> m_context;
};


int main(int argc, char* argv[])
{
    if (argc > 2) {
        return 666;
    }

    int number_of_engines = 1;
    if (argc == 2) {
        int num = atoi(argv[1]);
        if (num) {
            number_of_engines = num;
        } else {
            return 666;
        }
    }

    HandleScope scope;
    Persistent<Context> context = Context::New();
    Context::Scope context_scope(context);

    vector<EngineWithOwnIsolate* >* engines = new vector<EngineWithOwnIsolate* >();
    for (int i = 0; i < number_of_engines; ++i) {
        engines->push_back(new EngineWithOwnIsolate());
    }

    for (vector<EngineWithOwnIsolate*>::iterator it = engines->begin();
            it != engines->end();
            ++it) {
        delete *it;
    }


    delete engines;

    context.Dispose();
    return 0;
}



/*
 * Benchmark - Isolate/Context
 * Usage: pure-isolate-memtest [number_of_engines]
 * 
 */

#include <v8.h>
#include <vector>
#include <cstdlib>


using namespace v8;
using namespace std;


class EngineWithPureIsolate {
public:
    EngineWithPureIsolate()
    {
        m_isolate = Isolate::New();
    }

    ~EngineWithPureIsolate()
    {
        m_isolate->Dispose();
        printf("Destructor\n");
    }

private:
    EngineWithPureIsolate(const EngineWithPureIsolate&);
    EngineWithPureIsolate& operator=(const EngineWithPureIsolate&);

    Isolate* m_isolate;
};


int main(int argc, char* argv[])
{
    if (argc > 2) {
        return 666;
    }

    int number_of_engines = 1;
    if (argc == 2) {
        int num = atoi(argv[1]);
        if (num) {
            number_of_engines = num;
        } else {
            return 666;
        }
    }

    HandleScope scope;
    Persistent<Context> context = Context::New();
    Context::Scope context_scope(context);

    vector<EngineWithPureIsolate* >* engines = new vector<EngineWithPureIsolate* >();
    for (int i = 0; i < number_of_engines; ++i) {
        engines->push_back(new EngineWithPureIsolate());
    }

    for (vector<EngineWithPureIsolate*>::iterator it = engines->begin();
            it != engines->end();
            ++it) {
        delete *it;
    }

    delete engines;

    context.Dispose();
    return 0;
}



_______________________________________________
Qt-script mailing list
[email protected]
http://lists.qt.nokia.com/mailman/listinfo/qt-script

Reply via email to