Skip to content
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

fix: native extension: support older C++ ABIs #806

Merged
merged 18 commits into from
Oct 2, 2023
Merged
39 changes: 37 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ jobs:
- name: Build
run: npm run compile

platform-check:
centos-build-check:
runs-on: ubuntu-latest
strategy:
fail-fast: false
Expand All @@ -130,7 +130,7 @@ jobs:
include:
- container: 'centos:7'
- cmd: 'curl -sL https://rpm.nodesource.com/setup_${NODE_VERSION}.x | bash - && yum install -y nodejs gcc-c++ make'
name: Platform check - ${{ matrix.container }} - Node.js ${{ matrix.nodejs }}
name: CentOS build check - ${{ matrix.container }} - Node.js ${{ matrix.nodejs }}
container: ${{ matrix.container }}
env:
NODE_VERSION: ${{ matrix.nodejs }}
Expand All @@ -146,6 +146,41 @@ jobs:
- name: Run tests
run: npm run test

centos-prebuild-check:
needs: [prebuilds-linux]
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
container: ['centos:7']
nodejs: [14, 16]
include:
- container: 'centos:7'
nodejs: 14
cmd: 'curl -sL https://rpm.nodesource.com/setup_14.x | bash - && yum install -y nodejs'
- container: 'centos:7'
nodejs: 16
cmd: 'yum install https://rpm.nodesource.com/pub_16.x/nodistro/repo/nodesource-release-nodistro-1.noarch.rpm -y && yum install nodejs -y --setopt=nodesource-nodejs.module_hotfixes=1'
name: Centos check - ${{ matrix.container }} - Node.js ${{ matrix.nodejs }}
container: ${{ matrix.container }}
env:
NODE_VERSION: ${{ matrix.nodejs }}
steps:
- name: Setup container
run: ${{ matrix.cmd }}
- name: Checkout
uses: actions/checkout@v3
- name: Download
uses: actions/download-artifact@v3
- name: copy prebuilds
run: |
mkdir -p prebuilds
cp -r prebuilds-linux/* prebuilds
- name: Install npm dependencies
run: npm ci --ignore-scripts --no-optional --loglevel verbose
- name: Run tests
run: npm run test

e2e-local:
runs-on: ubuntu-latest
strategy:
Expand Down
3 changes: 2 additions & 1 deletion binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
"/WX"
],
"defines": [
"NOMINMAX"
"NOMINMAX",
"_WIN32_WINNT=0x0602"
],
"msvs_settings": {
"VCCLCompilerTool": {
Expand Down
57 changes: 22 additions & 35 deletions src/native_ext/memory_profiling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include "khash.h"
#include "util/platform.h"
#include <v8-profiler.h>
#include <vector>
#include "tinystl/vector.h"

namespace Splunk {
namespace Profiling {
Expand All @@ -16,8 +16,8 @@ enum MemoryProfilingStringIndex {
V8String_MAX
};

struct BFSNode {
BFSNode(v8::AllocationProfile::Node* node, uint32_t parentId) : node(node), parentId(parentId) {}
struct DFSNode {
DFSNode(v8::AllocationProfile::Node* node, uint32_t parentId) : node(node), parentId(parentId) {}
v8::AllocationProfile::Node* node;
uint32_t parentId;
};
Expand All @@ -31,11 +31,11 @@ struct MemoryProfiling {
uint64_t generation = 0;
// Used to keep track which were the new samples added to the allocation profile.
khash_t(SampleId) * tracking;
std::vector<BFSNode> stack;
bool isRunning = false;
tinystl::vector<DFSNode> stack;
bool v8ProfilerRunning = false;
};

MemoryProfiling* profiling = nullptr;
MemoryProfiling profiling;

struct StringStash {
v8::Local<v8::String> strings[V8String_MAX];
Expand All @@ -54,11 +54,7 @@ ToJsHeapNode(v8::AllocationProfile::Node* node, uint32_t parentId, StringStash*
} // namespace

NAN_METHOD(StartMemoryProfiling) {
if (!profiling) {
profiling = new MemoryProfiling();
}

if (profiling->isRunning) {
if (profiling.v8ProfilerRunning) {
return;
}

Expand Down Expand Up @@ -88,17 +84,13 @@ NAN_METHOD(StartMemoryProfiling) {
}
}

profiling->isRunning = profiler->StartSamplingHeapProfiler(sampleIntervalBytes, maxStackDepth);
profiling.v8ProfilerRunning = profiler->StartSamplingHeapProfiler(sampleIntervalBytes, maxStackDepth);
}

NAN_METHOD(CollectHeapProfile) {
info.GetReturnValue().SetNull();

if (!profiling) {
return;
}

if (!profiling->isRunning) {
if (!profiling.v8ProfilerRunning) {
return;
}

Expand All @@ -123,12 +115,12 @@ NAN_METHOD(CollectHeapProfile) {

v8::AllocationProfile::Node* root = profile->GetRootNode();

const std::vector<v8::AllocationProfile::Sample>& samples = profile->GetSamples();
const auto& samples = profile->GetSamples();

profiling->generation++;
uint64_t generation = profiling->generation;
profiling.generation++;
uint64_t generation = profiling.generation;

khash_t(SampleId)* tracking = profiling->tracking;
khash_t(SampleId)* tracking = profiling.tracking;

for (const auto& sample : samples) {
if (kh_get(SampleId, tracking, sample.sample_id) == kh_end(tracking)) {
Expand Down Expand Up @@ -165,16 +157,16 @@ NAN_METHOD(CollectHeapProfile) {
stash.strings[V8String_LineNumber] = Nan::New<v8::String>("lineNumber").ToLocalChecked();
stash.strings[V8String_ParentId] = Nan::New<v8::String>("parentId").ToLocalChecked();

std::vector<BFSNode>& stack = profiling->stack;
tinystl::vector<DFSNode>& stack = profiling.stack;
stack.clear();

// Cut off the root node
for (v8::AllocationProfile::Node* child : root->children) {
stack.emplace_back(child, root->node_id);
stack.push_back(DFSNode{child, root->node_id});
}

while (!stack.empty()) {
BFSNode graphNode = stack.back();
DFSNode graphNode = stack.back();
stack.pop_back();

v8::AllocationProfile::Node* node = graphNode.node;
Expand All @@ -183,7 +175,7 @@ NAN_METHOD(CollectHeapProfile) {
Nan::Set(jsNodeTree, Nan::New<v8::Uint32>(node->node_id), jsNode);

for (v8::AllocationProfile::Node* child : node->children) {
stack.emplace_back(child, node->node_id);
stack.push_back(DFSNode{child, node->node_id});
}
}

Expand All @@ -207,22 +199,17 @@ NAN_METHOD(CollectHeapProfile) {
}

NAN_METHOD(StopMemoryProfiling) {
if (!profiling) {
if (!profiling.v8ProfilerRunning) {
return;
}

if (profiling->isRunning) {
v8::HeapProfiler* profiler = info.GetIsolate()->GetHeapProfiler();

if (!profiler) {
return;
}
v8::HeapProfiler* profiler = info.GetIsolate()->GetHeapProfiler();

profiler->StopSamplingHeapProfiler();
if (!profiler) {
return;
}

delete profiling;
profiling = nullptr;
profiler->StopSamplingHeapProfiler();
}

} // namespace Profiling
Expand Down
37 changes: 28 additions & 9 deletions src/native_ext/metrics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,18 @@ int32_t GetGcStatsIndex(v8::GCType type) {
return -1;
}
}

enum GcType {
GcTypeAll,
GcTypeScavenge,
GcTypeMarkSweepCompact,
GcTypeIncrementalMarking,
GcTypeProcessWeakCallbacks,
};

struct GcCounters {
GcCounters(const std::string& type) : type(type) {}
std::string type;
GcCounters(GcType type) : type(type) {}
GcType type;
Counters time;
Counters amount;
};
Expand All @@ -72,11 +81,11 @@ const size_t kGcTypes = 5;
struct {
Counters eventLoop;
GcCounters gcCounters[kGcTypes] = {
{"all"},
{"scavenge"},
{"mark_sweep_compact"},
{"incremental_marking"},
{"process_weak_callbacks"}};
{GcTypeAll},
{GcTypeScavenge},
{GcTypeMarkSweepCompact},
{GcTypeIncrementalMarking},
{GcTypeProcessWeakCallbacks}};
} stats;

void EventLoopPrepareCallback(uv_prepare_t* handle) {
Expand All @@ -102,7 +111,7 @@ void EventLoopCheckCallback(uv_check_t* handle) {
#endif
}
void WriteCounters(
v8::Local<v8::Object>& parent, const std::string& key, const Counters& counters) {
v8::Local<v8::Object>& parent, const char* key, const Counters& counters) {
auto obj = Nan::New<v8::Object>();
Nan::Set(obj, Nan::New("min").ToLocalChecked(), Nan::New<v8::Number>(double(counters.min)));
Nan::Set(obj, Nan::New("max").ToLocalChecked(), Nan::New<v8::Number>(double(counters.max)));
Expand All @@ -113,6 +122,16 @@ void WriteCounters(
Nan::Set(parent, Nan::New(key).ToLocalChecked(), obj);
}

Nan::MaybeLocal<v8::String> GcTypeString(GcType type) {
switch (type) {
case GcTypeScavenge: return Nan::New("scavenge");
case GcTypeMarkSweepCompact: return Nan::New("mark_sweep_compact");
case GcTypeIncrementalMarking: return Nan::New("incremental_marking");
case GcTypeProcessWeakCallbacks: return Nan::New("process_weak_callbacks");
default: return Nan::New("all");
}
}

NAN_GC_CALLBACK(GcPrologue) {
state.gc.startTime = uv_hrtime();
v8::HeapStatistics heapStats;
Expand Down Expand Up @@ -151,7 +170,7 @@ NAN_METHOD(CollectCounters) {
auto typeObj = Nan::New<v8::Object>();
WriteCounters(typeObj, "collected", gcStats.amount);
WriteCounters(typeObj, "duration", gcStats.time);
Nan::Set(gcObj, Nan::New(gcStats.type).ToLocalChecked(), typeObj);
Nan::Set(gcObj, GcTypeString(gcStats.type).ToLocalChecked(), typeObj);
}

Nan::Set(obj, Nan::New("gc").ToLocalChecked(), gcObj);
Expand Down
50 changes: 50 additions & 0 deletions src/native_ext/tinystl/allocator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*-
* Copyright 2012 Matthew Endsley
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted providing that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef TINYSTL_ALLOCATOR_H
#define TINYSTL_ALLOCATOR_H

#include "stddef.h"

#ifndef TINYSTL_ALLOCATOR

namespace tinystl {

struct allocator {
static void* static_allocate(size_t bytes) {
return operator new(bytes);
}

static void static_deallocate(void* ptr, size_t /*bytes*/) {
operator delete(ptr);
}
};
}

# define TINYSTL_ALLOCATOR ::tinystl::allocator
#endif // TINYSTL_ALLOCATOR

#endif
Loading
Loading