Hi all!

This mail is about the ExternalResource benchmark. I checked the modifications sent by Kent and I modified it. Now none of the Point objects are freed before the call of V8::IdleNotification(). I attached the modified code to this mail.

Here is a sample run:

*** Begin MeasureExternalResource ***
Scavenge 0.9 -> 0.8 MB, 2 ms.
Scavenge 1.1 -> 1.1 MB, 1 ms.
Scavenge 1.4 -> 1.3 MB, 1 ms.
Scavenge 1.8 -> 1.7 MB, 2 ms.
Mark-sweep 2.5 -> 2.1 MB, 6 ms.
Scavenge 3.1 -> 3.1 MB, 3 ms.
Mark-sweep 6.4 -> 4.9 MB, 17 ms.
Mark-sweep 8.5 -> 7.4 MB, 24 ms.
Mark-sweep 13.9 -> 12.2 MB, 43 ms.
Mark-sweep 19.2 -> 16.7 MB, 53 ms.
Number of Point objects before IdleNotification: 1000000
Scavenge 25.0 -> 25.0 MB, 21 ms.
Mark-sweep 25.0 -> 0.4 MB, 202 ms.
Mark-compact 0.4 -> 0.4 MB, 4 ms.
*** End MeasureExternalResource ***
*** Begin MeasureMakeWeak ***
Scavenge 1.1 -> 0.9 MB, 1 ms.
Scavenge 1.2 -> 1.2 MB, 2 ms.
Scavenge 1.5 -> 1.5 MB, 1 ms.
Scavenge 2.0 -> 2.0 MB, 4 ms.
Mark-sweep 2.8 -> 2.2 MB, 10 ms.
Scavenge 4.9 -> 4.4 MB, 8 ms.
Scavenge 7.0 -> 7.0 MB, 11 ms.
Mark-sweep 14.1 -> 10.3 MB, 2 / 47 ms.
Mark-sweep 18.0 -> 15.6 MB, 3 / 64 ms.
Number of Point objects before IdleNotification: 1000000
Scavenge 25.1 -> 25.1 MB, 34 ms.
Mark-sweep 25.1 -> 21.4 MB, 143 / 226 ms.
Mark-compact 21.4 -> 0.4 MB, 12 ms.
*** End MeasureMakeWeak ***
Mean of ExternalResource      : 230.21 ms.
Deviation of ExternalResource : 0.00 ms.
Mean of MakeWeak              : 275.15 ms.
Deviation of MakeWeak         : 0.00 ms.

Best regards,
Gabor Ballabas


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

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

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


using namespace v8;
using namespace std;


void ExecuteString(v8::Handle<v8::String> source, bool print_result)
{
    v8::HandleScope handle_scope;
    v8::TryCatch try_catch;
    v8::Handle<v8::Script> script = v8::Script::Compile(source);
    assert(!script.IsEmpty());
    v8::Handle<v8::Value> result = script->Run();
    assert(!result.IsEmpty());
    if (print_result) {
        v8::String::Utf8Value str(result);
        printf("%s\n", *str);
    }
}



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;
        V8::AdjustAmountOfExternalAllocatedMemory(-int(sizeof(V8PointResource) + sizeof(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;
}


static Handle<Value> makeResourcePoint(const Arguments& args)
{
    assert(args.IsConstructCall());
    Local<Object> self = args.This();
    Point* p = new Point(10, 20);
    V8PointResource* point_resource = new V8PointResource(p);
    V8::AdjustAmountOfExternalAllocatedMemory(int(sizeof(V8PointResource) + sizeof(Point)));
    self->SetExternalResource(point_resource);
    return v8::Undefined();
}

static Handle<Value> getResourcePointX(Local<String>, const AccessorInfo &info)
{
    Local<Object> self = info.Holder();
    V8PointResource *res = v8_resource_cast<V8PointResource>(self);
    assert(res != 0);
    return v8::Int32::New(res->point->x_);
}

static Handle<Value> getResourcePointY(Local<String>, const AccessorInfo &info)
{
    Local<Object> self = info.Holder();
    V8PointResource *res = v8_resource_cast<V8PointResource>(self);
    assert(res != 0);
    return v8::Int32::New(res->point->y_);
}



void weakPointCallback(Persistent<Value> object, void* parameter)
{
    Point* point = static_cast<Point*>(parameter);
    delete point;
    object.Dispose();
    object.Clear();
    V8::AdjustAmountOfExternalAllocatedMemory(-int(sizeof(Point)));
}

static Handle<Value> makeWeakPoint(const Arguments& args)
{
    assert(args.IsConstructCall());
    Local<Object> self = args.This();
    assert(self->InternalFieldCount() == 1);
    Point *point = new Point(10, 20);
    self->SetPointerInInternalField(0, point);
    V8::AdjustAmountOfExternalAllocatedMemory(int(sizeof(Point)));
    Persistent<Object> weakSelf = Persistent<Object>::New(self);
    weakSelf.MakeWeak(point, weakPointCallback);
    return weakSelf;
}

static Handle<Value> getWeakPointX(Local<String>, const AccessorInfo &info)
{
    Local<Object> self = info.Holder();
    Point *point = static_cast<Point*>(self->GetPointerFromInternalField(0));
    return v8::Int32::New(point->x_);
}

static Handle<Value> getWeakPointY(Local<String>, const AccessorInfo &info)
{
    Local<Object> self = info.Holder();
    Point *point = static_cast<Point*>(self->GetPointerFromInternalField(0));
    return v8::Int32::New(point->y_);
}



void MeasureExternalResource(int number_of_objects, Tester* tester)
{
    printf("*** Begin MeasureExternalResource ***\n");

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

        v8::Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(makeResourcePoint);
        v8::Handle<v8::ObjectTemplate> point_templ = fun_templ->InstanceTemplate();
        point_templ->SetHasExternalResource(true);
        point_templ->SetAccessor(v8::String::New("x"), getResourcePointX);
        point_templ->SetAccessor(v8::String::New("y"), getResourcePointY);

    
        HandleScope scope;

        v8::Context::GetEntered()->Global()->Set(v8::String::New("Point"), fun_templ->GetFunction());
        v8::Context::GetEntered()->Global()->Set(v8::String::New("counter"), v8::Int32::New(number_of_objects));

        ExecuteString(v8::String::New("var points = new Array();"
                                      "for (i = 0; i < counter; ++i) { points[i] = new Point(); }"),
                                      false);

        context.Dispose();
    }

    printf("Number of Point objects before IdleNotification: %d\n", Point::counter);

    tester->startMeasuring();
    while (!V8::IdleNotification()) { }
    tester->endMeasuring();
    assert(Point::counter == 0);

    printf("*** End MeasureExternalResource ***\n");
}


void MeasureMakeWeak(int number_of_objects, Tester* tester)
{
    printf("*** Begin MeasureMakeWeak ***\n");
    
    {   
        Persistent<Context> context = Context::New();
        Context::Scope context_scope(context);
        v8::Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(makeWeakPoint);
        v8::Handle<v8::ObjectTemplate> point_templ = fun_templ->InstanceTemplate();
        point_templ->SetInternalFieldCount(1);
        point_templ->SetAccessor(v8::String::New("x"), getWeakPointX);
        point_templ->SetAccessor(v8::String::New("y"), getWeakPointY);

    
        HandleScope scope;

        v8::Context::GetEntered()->Global()->Set(v8::String::New("Point"), fun_templ->GetFunction());
        v8::Context::GetEntered()->Global()->Set(v8::String::New("counter"), v8::Int32::New(number_of_objects));

        ExecuteString(v8::String::New("var points = new Array();"
                                      "for (i = 0; i < counter; ++i) { points[i] = new Point(); }"),
                                      false);

        context.Dispose();
    }

    printf("Number of Point objects before IdleNotification: %d\n", Point::counter);

    tester->startMeasuring();
    while (!V8::IdleNotification()) { }
    tester->endMeasuring();
    assert(Point::counter == 0);

    printf("*** End MeasureMakeWeak ***\n");
}


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;
        }
    }

    const char *v8args = getenv("V8ARGS");
    if (v8args)
        v8::V8::SetFlagsFromString(v8args, strlen(v8args));

    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 = 1000000;

    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("Mean of MakeWeak              : %.2lf ms.\n", weakTester->getMean());
    printf("Deviation of MakeWeak         : %.2lf ms.\n", weakTester->getDeviation());

    context.Dispose();

    return 0;
}


#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;
}


#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
_______________________________________________
Qt-script mailing list
[email protected]
http://lists.qt.nokia.com/mailman/listinfo/qt-script

Reply via email to