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