Permalink
Browse files

core, feat: support collecting code coverage information.

  • Loading branch information...
xicilion committed Oct 30, 2017
1 parent 600764b commit b385d6939f751b29e64aaebfc7a56d49506eb5ba
Showing with 43 additions and 27 deletions.
  1. +1 −1 fibjs/include/v8_api.h
  2. +4 −1 fibjs/src/base/Runtime.cpp
  3. +13 −5 fibjs/src/base/options.cpp
  4. +17 −20 fibjs/src/base/v8_api.cpp
  5. +8 −0 fibjs/src/process/process.cpp
View
@@ -20,8 +20,8 @@ V8FrameInfo save_fi(v8::Isolate* isolate);
exlib::string traceInfo(v8::Isolate* isolate, int32_t deep, void* entry_fp, void* handle);
exlib::string traceInfo(v8::Isolate* isolate, int32_t deep);
void WriteLcovData(v8::Isolate* isolate, exlib::string file);
void beginCoverage(v8::Isolate* isolate);
void WriteLcovData(v8::Isolate* isolate, const char* file);
} /* namespace fibjs */
@@ -169,6 +169,9 @@ void Isolate::init()
v8::Context::Scope context_scope(_context);
if (g_cov && m_id == 1)
beginCoverage(m_isolate);
_context->SetEmbedderData(1, v8::Object::New(m_isolate)->GetPrototype());
static const char* skips[] = { "Master", "repl", "argv", "__filename", "__dirname", NULL };
@@ -183,7 +186,7 @@ void Isolate::start_profiler()
if (g_prof) {
char name[32];
obj_ptr<Timer_base> tm;
sprintf(name, "fibjs-%p.log", this);
sprintf(name, "fibjs-%08x.log", (uint32_t)(intptr_t)this);
profiler_base::start(name, -1, g_prof_interval, tm);
m_pendding.dec();
}
View
@@ -24,6 +24,8 @@ int32_t stack_size = 256;
bool g_prof = false;
int32_t g_prof_interval = 1000;
bool g_cov = false;
#ifdef DEBUG
#define GUARD_SIZE 32
#else
@@ -37,15 +39,18 @@ static void printHelp()
puts("Usage: fibjs [options] [script.js] [arguments] \n"
"\n"
"Options:\n"
" -h, --help print fibjs command line options\n"
" -v, --version print fibjs version\n"
" -h, --help print fibjs command line options.\n"
" -v, --version print fibjs version.\n"
"\n"
" --prof log statistical profiling information.\n"
" --prof-interval=n interval for --prof samples (in microseconds, default: 1000).\n"
" --prof-process process log file generated by profiler.start\n"
" --prof-process process log file generated by profiler.start.\n"
"\n"
" --v8-options print v8 command line options\n"
" --cov collecting code coverage information (only work on the main Worker).\n"
"\n"
"Documentation can be found at http://fibjs.org/\n");
" --v8-options print v8 command line options.\n"
"\n"
"Documentation can be found at http://fibjs.org\n");
}
void options(int32_t& pos, char* argv[])
@@ -84,6 +89,9 @@ void options(int32_t& pos, char* argv[])
if (g_prof_interval < 50)
g_prof_interval = 50;
df++;
} else if (!qstrcmp(arg, "--cov")) {
g_cov = true;
df++;
} else if (!qstrcmp(arg, "--v8-options")) {
v8::internal::FlagList::PrintHelp();
_exit(0);
View
@@ -19,7 +19,6 @@
#include "exlib/include/qstring.h"
#include "v8_api.h"
#include <fstream>
namespace fibjs {
@@ -137,23 +136,23 @@ inline void WriteLcovDataForRange(std::vector<uint32_t>& lines, int start_line,
lines[k] = count;
}
inline void WriteLcovDataForNamedRange(std::ostream& sink,
std::vector<uint32_t>& lines, std::string name,
int start_line, int end_line, uint32_t count)
inline void WriteLcovDataForNamedRange(FILE* sink,
std::vector<uint32_t>& lines, std::string name, int start_line, int end_line, uint32_t count)
{
WriteLcovDataForRange(lines, start_line, end_line, count);
sink << "FN:" << start_line + 1 << "," << name << std::endl;
sink << "FNDA:" << count << "," << name << std::endl;
fprintf(sink, "FN:%d,%s\n", start_line + 1, name.c_str());
fprintf(sink, "FNDA:%d,%s\n", count, name.c_str());
}
void WriteLcovData(v8::Isolate* isolate, exlib::string file)
void WriteLcovData(v8::Isolate* isolate, const char* file)
{
v8::HandleScope handle_scope(isolate);
v8::debug::Coverage::SelectMode(isolate, v8::debug::Coverage::kBestEffort);
FILE* sink = fopen(file, "a");
if (sink == NULL)
return;
v8::HandleScope handle_scope(isolate);
v8::debug::Coverage coverage = v8::debug::Coverage::CollectPrecise(isolate);
std::ofstream sink(file.c_str(), std::ofstream::app);
for (size_t i = 0; i < coverage.ScriptCount(); i++) {
v8::debug::Coverage::ScriptData script_data = coverage.GetScriptData(i);
v8::Local<v8::debug::Script> script = script_data.GetScript();
@@ -162,11 +161,7 @@ void WriteLcovData(v8::Isolate* isolate, exlib::string file)
if (!script->Name().ToLocal(&name))
continue;
std::string file_name = ToSTLString(isolate, name);
// Skip scripts not backed by a file.
if (!std::ifstream(file_name).good())
continue;
sink << "SF:";
sink << file_name << std::endl;
fprintf(sink, "SF:%s\n", file_name.c_str());
std::vector<uint32_t> lines;
for (size_t j = 0; j < script_data.FunctionCount(); j++) {
v8::debug::Coverage::FunctionData function_data = script_data.GetFunctionData(j);
@@ -202,10 +197,12 @@ void WriteLcovData(v8::Isolate* isolate, exlib::string file)
}
}
// Write per-line coverage. LCOV uses 1-based line numbers.
for (size_t i = 0; i < lines.size(); i++) {
sink << "DA:" << (i + 1) << "," << lines[i] << std::endl;
}
sink << "end_of_record" << std::endl;
for (size_t i = 0; i < lines.size(); i++)
fprintf(sink, "DA:%d,%d\n", (int32_t)(i + 1), lines[i]);
fprintf(sink, "end_of_record\n");
}
fclose(sink);
}
}
@@ -18,6 +18,8 @@
#include "SubProcess.h"
#include <vector>
#include "process_hrtime.h"
#include "options.h"
#include "v8_api.h"
#ifdef _WIN32
#include <psapi.h>
@@ -265,6 +267,12 @@ result_t process_base::exit()
flushLog();
if (g_cov && isolate->m_id == 1) {
char name[32];
sprintf(name, "fibjs-%08x.lcov", (uint32_t)(intptr_t)isolate);
WriteLcovData(isolate->m_isolate, name);
}
#ifdef _WIN32
TerminateProcess(GetCurrentProcess(), code);
#else

0 comments on commit b385d69

Please sign in to comment.