-
Notifications
You must be signed in to change notification settings - Fork 384
Add CPU profiling and heap snapshot information; add IntelliJ files to .gitignore #114
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,3 +8,9 @@ build/ | |
| *.dll | ||
| *.dylib | ||
| hs_err*.log | ||
|
|
||
| # Intellij project files | ||
| *.iml | ||
| *.ipr | ||
| *.iws | ||
| .idea | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,6 +7,7 @@ sed s/\$\{arch\}/x86_64/g < pom1.xml > pom.xml | |
| mvn -Dos=macosx -Darch=x86_64 clean install | ||
| cp pom_template.xml pom.xml | ||
| rm pom1.xml | ||
| rm pom_template.xml | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe I'm missing some part in the build process as to why this file isn't cleaned up in this script, but the result of not deleting it is that it leaves a file that Git then detects as a change, leaving my working state dirty even if I made no changes. |
||
| STATUS=$? | ||
| if [ $STATUS -eq 0 ]; then | ||
| echo "MacOS Build Successful" | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,8 +12,11 @@ | |
| #include <iostream> | ||
| #include <v8-debug.h> | ||
| #include <v8.h> | ||
| #include <v8-profiler.h> | ||
| #include <map> | ||
| #include <cstdlib> | ||
| #include <fstream> | ||
| #include <sstream> | ||
| #include "com_eclipsesource_v8_V8Impl.h" | ||
| #pragma comment(lib, "Ws2_32.lib") | ||
| #pragma comment(lib, "WINMM.lib") | ||
|
|
@@ -1469,3 +1472,215 @@ JNIEXPORT jlong JNICALL Java_com_eclipsesource_v8_V8__1getBuildID | |
| (JNIEnv *, jobject) { | ||
| return 2; | ||
| } | ||
|
|
||
| /***** Serializes objects to JSON on the fly (used by code to serialize profiling information to file) *****/ | ||
|
|
||
| static void findAndReplace(string& source, const string find, const string replace) | ||
| { | ||
| string::size_type i = 0; | ||
| while((i = source.find(find, i)) != string::npos) { | ||
| source.replace(i, find.length(), replace); | ||
| i += replace.length(); | ||
| } | ||
| } | ||
|
|
||
| class JsonSerializer { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There may be a third party library I could use for this, but I was trying to keep things simple as it's not a complicated class. Also, if you did know of a library, it would need to support writing the serialized json on the fly (compared to just taking in an object and spitting out a string) |
||
| public: | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you want, I can split out this class into separate header/cpp files. I left it currently in place as this prevents changes you would potentially have to make to the build process (as the g++ command would now have new files) |
||
| void startObject(string name = ""); | ||
| void endObject(bool isDoneAdding = false); | ||
| void startArray(string name = ""); | ||
| void endArray(bool isDoneAdding = false); | ||
| template<class T> void addValue(T value, bool quoteValue, bool isDoneAdding = false); | ||
| template<class T> void addProperty(string name, T value, bool quoteValue, bool isDoneAdding = false); | ||
| string getJson(); | ||
| private: | ||
| stringstream json; | ||
| template<class T> void addQuotedValue(T value); | ||
| template<class T> void addValueImpl(T value, bool quoteValue, bool isDoneAdding = false); | ||
| void addPropertyName(string name); | ||
| void doneAdding(bool isDoneAdding); | ||
| }; | ||
|
|
||
| void JsonSerializer::startObject(string name) { | ||
| addPropertyName(name); | ||
| json << "{"; | ||
| } | ||
|
|
||
| void JsonSerializer::endObject(bool isDoneAdding) { | ||
| json << "}"; | ||
| doneAdding(isDoneAdding); | ||
| } | ||
|
|
||
| void JsonSerializer::startArray(string name) { | ||
| addPropertyName(name); | ||
| json << "["; | ||
| } | ||
|
|
||
| void JsonSerializer::endArray(bool isDoneAdding) { | ||
| json << "]"; | ||
| doneAdding(isDoneAdding); | ||
| } | ||
|
|
||
| template<class T> void JsonSerializer::addQuotedValue(T value) { | ||
| json << "\"" << value << "\""; | ||
| } | ||
|
|
||
| template<class T> void JsonSerializer::addValueImpl(T value, bool quoteValue, bool isDoneAdding) { | ||
| if(quoteValue) { | ||
| addQuotedValue(value); | ||
| } else { | ||
| json << value; | ||
| } | ||
| doneAdding(isDoneAdding); | ||
| } | ||
|
|
||
| template<class T> void JsonSerializer::addValue(T value, bool quoteValue, bool isDoneAdding) { | ||
| addValueImpl(value, quoteValue, isDoneAdding); | ||
| } | ||
|
|
||
| template<> void JsonSerializer::addValue(string value, bool quoteValue, bool isDoneAdding) { | ||
| findAndReplace(value, "\\", "\\\\"); // backslash needs to be escaped for valid JSON | ||
| addValueImpl(value, quoteValue, isDoneAdding); | ||
| } | ||
|
|
||
| template<class T> void JsonSerializer::addProperty(string name, T value, bool quoteValue, bool isDoneAdding) { | ||
| addPropertyName(name); | ||
| addValue(value, quoteValue, isDoneAdding); | ||
| } | ||
|
|
||
| void JsonSerializer::addPropertyName(string name) { | ||
| if(name != "") { | ||
| addQuotedValue(name); | ||
| json << ":"; | ||
| } | ||
| } | ||
|
|
||
| void JsonSerializer::doneAdding(bool isDoneAdding) { | ||
| if(!isDoneAdding) { | ||
| json << ","; | ||
| } | ||
| } | ||
|
|
||
| string JsonSerializer::getJson() { | ||
| return json.str(); | ||
| } | ||
|
|
||
| /***** Output stream that writes to file (used by code to serialize heap information to file) *****/ | ||
|
|
||
| class HeapSnapshotFileOutputStream : public v8::OutputStream { | ||
| public: | ||
| HeapSnapshotFileOutputStream(string fileName) { file.open(fileName.c_str()); } | ||
|
|
||
| virtual void EndOfStream() { file.close(); } | ||
|
|
||
| virtual WriteResult WriteAsciiChunk(char* buffer, int size) { | ||
| file.write(buffer, size); | ||
| file.flush(); | ||
| return kContinue; | ||
| } | ||
|
|
||
| private: | ||
| ofstream file; | ||
| }; | ||
|
|
||
| /***** Writes the profile information to a file in a standard format (*.cpuprofile) *****/ | ||
|
|
||
| static void walkCpuProfileNode(const CpuProfileNode* node, JsonSerializer* serializer) { | ||
| String::Utf8Value functionName(node->GetFunctionName()); | ||
| String::Utf8Value scriptResourceName(node->GetScriptResourceName()); | ||
| serializer->addProperty("functionName", string(*functionName), true); | ||
| serializer->addProperty("scriptId", node->GetScriptId(), true); | ||
| serializer->addProperty("url", string(*scriptResourceName), true); | ||
| serializer->addProperty("lineNumber", node->GetLineNumber(), false); | ||
| serializer->addProperty("columnNumber", node->GetColumnNumber(), false); | ||
| serializer->addProperty("hitCount", node->GetHitCount(), false); | ||
| serializer->addProperty("callUID", node->GetCallUid(), false); | ||
| serializer->addProperty("id", node->GetNodeId(), false); | ||
| serializer->addProperty("bailoutReason", node->GetBailoutReason(), true); | ||
| serializer->startArray("positionTicks"); | ||
| serializer->endArray(); | ||
|
|
||
| // recursively walk through the child nodes | ||
| serializer->startArray("children"); | ||
| int numChildren = node->GetChildrenCount(); | ||
| for(int i = 0; i < numChildren; i++) { | ||
| serializer->startObject(); | ||
| walkCpuProfileNode(node->GetChild(i), serializer); | ||
| serializer->endObject(i == (numChildren - 1)); | ||
| } | ||
| serializer->endArray(true); | ||
| } | ||
|
|
||
| static void serializeProfileToFile(CpuProfile* profile, char* filePath) { | ||
| ofstream cpuProfileFile; | ||
| cpuProfileFile.open(filePath); | ||
|
|
||
| JsonSerializer* serializer = new JsonSerializer(); | ||
| serializer->startObject(); | ||
|
|
||
| serializer->startObject("head"); | ||
| walkCpuProfileNode(profile->GetTopDownRoot(), serializer); | ||
| serializer->endObject(); | ||
|
|
||
| // get times and convert from microseconds to seconds | ||
| serializer->addProperty("startTime", profile->GetStartTime() / 1000000.0, false); | ||
| serializer->addProperty("endTime", profile->GetEndTime() / 1000000.0, false); | ||
|
|
||
| int sampleCount = profile->GetSamplesCount(); | ||
|
|
||
| serializer->startArray("samples"); | ||
| for(int i = 0; i < sampleCount; i++){ | ||
| serializer->addValue(profile->GetSample(i)->GetNodeId(), false, i == (sampleCount - 1)); | ||
| } | ||
| serializer->endArray(); | ||
|
|
||
| serializer->startArray("timestamps"); | ||
| for(int i = 0; i < sampleCount; i++){ | ||
| serializer->addValue(profile->GetSampleTimestamp(i), false, i == (sampleCount - 1)); | ||
| } | ||
| serializer->endArray(true); | ||
|
|
||
| serializer-> endObject(true); | ||
| cpuProfileFile << serializer->getJson(); | ||
| cpuProfileFile.close(); | ||
| } | ||
|
|
||
| /***** Writes the heap snapshot information to a file in a standard format (*.heapsnapshot) *****/ | ||
|
|
||
| static void serializeHeapSnapshotToFile(const HeapSnapshot* heapSnapshot, char* filePath) { | ||
| HeapSnapshotFileOutputStream* heapSnapshotFile = new HeapSnapshotFileOutputStream(filePath); | ||
| heapSnapshot->Serialize(heapSnapshotFile, HeapSnapshot::kJSON); | ||
| } | ||
|
|
||
| /***** Starts and stops the profiling session *****/ | ||
|
|
||
| JNIEXPORT void JNICALL Java_com_eclipsesource_v8_V8__1startProfiling | ||
| (JNIEnv *env, jobject, jlong v8RuntimePtr, jstring profileTitle) { | ||
| Isolate* isolate = SETUP(env, v8RuntimePtr, ); | ||
| Local<String> title = createV8String(env, isolate, profileTitle); | ||
| isolate->GetCpuProfiler()->StartProfiling(title, true); | ||
| } | ||
|
|
||
| JNIEXPORT void JNICALL Java_com_eclipsesource_v8_V8__1stopProfiling | ||
| (JNIEnv *env, jobject, jlong v8RuntimePtr, jstring profileTitle, jstring filePath) { | ||
| Isolate* isolate = SETUP(env, v8RuntimePtr, ); | ||
| Local<String> title = createV8String(env, isolate, profileTitle); | ||
| Local<String> path = createV8String(env, isolate, filePath); | ||
| String::Utf8Value strPath(path); | ||
| CpuProfile* profile = isolate->GetCpuProfiler()->StopProfiling(title); | ||
| serializeProfileToFile(profile, *strPath); | ||
| profile->Delete(); | ||
| } | ||
|
|
||
| /***** Takes a snapshot of the current objects on the heap *****/ | ||
|
|
||
| JNIEXPORT void JNICALL Java_com_eclipsesource_v8_V8__1takeHeapSnapshot | ||
| (JNIEnv *env, jobject, jlong v8RuntimePtr, jstring profileTitle, jstring filePath) { | ||
| Isolate* isolate = SETUP(env, v8RuntimePtr, ); | ||
| Local<String> title = createV8String(env, isolate, profileTitle); | ||
| Local<String> path = createV8String(env, isolate, filePath); | ||
| String::Utf8Value strPath(path); | ||
| const HeapSnapshot* heapSnapshot = isolate->GetHeapProfiler()->TakeHeapSnapshot(title); | ||
| serializeHeapSnapshotToFile(heapSnapshot, *strPath); | ||
| const_cast<v8::HeapSnapshot*>(heapSnapshot)->Delete(); | ||
| } | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I use IntelliJ rather than Eclipse, and there are a different set of local user-specific project files that should be ignored by Git