On 2011-03-03, at 3:20 PM, Bruno Dufour wrote:
AFAIK, v8 is not in our repo, so emailing the patch file to the list works too :)
My changes were "quick and dirty". I added 3 lines to src/heap.cc (look for <=== ADDED): extern "C" { double bytes_allocated = 0, bytes_alive_at_last_gc = 0; } // <=== ADDED void Heap::GarbageCollectionPrologue() { double n = SizeOfObjects(); bytes_allocated += n-bytes_alive_at_last_gc; // <=== ADDED TranscendentalCache::Clear(); ClearJSFunctionResultCaches(); ... void Heap::GarbageCollectionEpilogue() { ... Counters::alive_after_last_gc.Set(static_cast<int>(SizeOfObjects())); bytes_alive_at_last_gc = SizeOfObjects(); // <=== ADDED Counters::symbol_table_capacity.Set(symbol_table()->Capacity()); Counters::number_of_symbols.Set(symbol_table()->NumberOfElements()); #if defined(DEBUG) || defined(ENABLE_LOGGING_AND_PROFILING) ReportStatisticsAfterGC(); #endif #ifdef ENABLE_DEBUGGER_SUPPORT Debug::AfterGarbageCollection(); #endif } And in d8-tachyon-exts.cc I added some functions: v8::Handle<v8::Value> v8Proxy_timeCurrentMillis(const v8::Arguments& args) { if (args.Length() != 0) { printf("Error in timeCurrentMillis -- 0 argument expected\n"); exit(1); } return v8::Number::New(v8::internal::OS::TimeCurrentMillis()); } extern "C" { extern double bytes_allocated, bytes_alive_at_last_gc; // defined in src/heap.cc } v8::Handle<v8::Value> v8Proxy_bytesAllocated(const v8::Arguments& args) { if (args.Length() != 0) { printf("Error in bytesAllocated -- 0 argument expected\n"); exit(1); } return v8::Number::New(bytes_allocated + (v8::internal::Heap::SizeOfObjects()-bytes_alive_at_last_gc)); } and in the function init_d8_extensions I added: global_template->Set( v8::String::New("timeCurrentMillis"), v8::FunctionTemplate::New(v8Proxy_timeCurrentMillis) ); global_template->Set( v8::String::New("bytesAllocated"), v8::FunctionTemplate::New(v8Proxy_bytesAllocated) ); These two functions are used in the implementation of the performance measurement code (in utility/misc.js): function PerfInfo() { this.time = 0; this.bytes_alloc = 0; this.buckets = {}; } var perfBuckets = {}; function measurePerformance(bucket, thunk) { var perfInfo; if (!perfBuckets.hasOwnProperty(bucket)) { perfInfo = new PerfInfo(); perfBuckets[bucket] = perfInfo; } else { perfInfo = perfBuckets[bucket]; } var perfBucketsOld = perfBuckets; perfBuckets = perfInfo.buckets; var start_time = timeCurrentMillis(); var start_bytes_alloc = bytesAllocated(); var result = thunk(); var bytes_alloc = bytesAllocated() - start_bytes_alloc; var time = timeCurrentMillis() - start_time; perfBuckets = perfBucketsOld; perfInfo.time += time; perfInfo.bytes_alloc += bytes_alloc; return result; } function reportPerformance() { print("******************** Performance report"); for (var bucket in perfBuckets) { var perfInfo = perfBuckets[bucket]; print(""); print(bucket + ": " + perfInfo.time/1000 + " s, " + perfInfo.bytes_alloc/(1024*1024) + " MB allocated"); reportPerformanceSubBuckets(perfInfo, perfInfo.buckets, ""); } print(""); print("********************"); } function reportPerformanceSubBuckets(overall, buckets, indent) { indent += " "; var sortedBuckets = []; for (var bucket in buckets) sortedBuckets.push(bucket); sortedBuckets = sortedBuckets.sort( function (x, y) { return buckets[x].time < buckets[y].time; }); for (var i = 0; i<sortedBuckets.length; i++) { var bucket = sortedBuckets[i]; var perfInfo = buckets[bucket]; print(indent + "time=" + Math.floor(perfInfo.time*100/overall.time) + "% " + "alloc=" + Math.floor(perfInfo.bytes_alloc*100/overall.bytes_alloc) + "%" + " -- " + bucket); reportPerformanceSubBuckets(overall, perfInfo.buckets, indent); } } That way, wherever some code needs to be monitored for execution time and space usage, all that is needed is a call like: measurePerformance( "Compiling Tachyon", function () { // Compile the Tachyon sources tachyonIRs = compSources(tachyonSrcs, params); }); and eventually reportPerformance(); Marc