Skip to content
Snippets Groups Projects
Commit 141159e5 authored by Avi Kivity's avatar Avi Kivity
Browse files

Merge branch 'cli'

- per-cpu variables
- per-cpu kvmclock
- tracepoint probe functions
- tracepoint Java API
- 'perf stat' cli command
parents f8a4ece3 092f28c6
No related branches found
No related tags found
No related merge requests found
Showing with 682 additions and 36 deletions
......@@ -25,6 +25,11 @@ SECTIONS
_init_array_start = .;
.init_array : { *(SORT_BY_INIT_PRIORITY(.init_array.*)) } :text
_init_array_end = .;
.percpu : {
_percpu_start = .;
*(.percpu)
_percpu_end = .;
}
.tls_template_start = .;
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } :tls :text
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) } :tls :text
......
......@@ -46,8 +46,7 @@ void parse_madt()
if (!(lapic->LapicFlags & ACPI_MADT_ENABLED)) {
break;
}
auto c = new sched::cpu;
c->id = idgen++;
auto c = new sched::cpu(idgen++);
c->arch.apic_id = lapic->Id;
c->arch.acpi_id = lapic->ProcessorId;
c->arch.initstack.next = smp_stack_free;
......
......@@ -101,6 +101,7 @@
/usr/lib/&/jni/elf-loader.so: java/&
/usr/lib/&/jni/networking.so: java/&
/usr/lib/&/jni/stty.so: java/&
/usr/lib/&/jni/tracepoint.so: java/&
/tools/ifconfig.so: ./tools/ifconfig/ifconfig.so
/tools/lsroute.so: ./tools/route/lsroute.so
/console/util.js: ../../console/util.js
......@@ -120,4 +121,5 @@
/console/cli.js: ../../console/cli.js
/console/init.js: ../../console/init.js
/console/md5sum.js: ../../console/md5sum.js
/&/console/perf.js: ../../&
/&/etc/hosts: ../../static/&
......@@ -437,6 +437,8 @@ objects += core/trace.o
objects += core/poll.o
objects += core/select.o
objects += core/power.o
objects += core/percpu.o
objects += core/per-cpu-counter.o
include $(src)/fs/build.mak
include $(src)/libc/build.mak
......@@ -490,7 +492,7 @@ usr.img: usr.manifest
sh $(src)/scripts/mkromfs.sh, MKROMFS $@)
jni = java/jni/balloon.so java/jni/elf-loader.so java/jni/networking.so \
java/jni/stty.so
java/jni/stty.so java/jni/tracepoint.so
$(jni): INCLUDES += -I /usr/lib/jvm/java/include -I /usr/lib/jvm/java/include/linux/
bootfs.bin: scripts/mkbootfs.py bootfs.manifest $(tests) $(tools) $(jni) \
......
importPackage(java.io);
importPackage(java.lang);
importPackage(com.cloudius.util);
importPackage(com.cloudius.cli.util);
......@@ -18,6 +17,7 @@ load("/console/arp.js");
load("/console/md5sum.js");
load("/console/route.js");
load("/console/java.js");
load("/console/perf.js");
// Commands
var _commands = new Array();
......@@ -33,10 +33,13 @@ _commands["arp"] = arp_cmd;
_commands["route"] = route_cmd;
_commands["md5sum"] = md5sum_cmd;
_commands["java"] = java_cmd;
_commands["perf"] = perf_cmd;
// Create interface to networking functions
var networking_interface = new Networking();
var System = java.lang.System
// I/O
var _reader = new BufferedReader( new InputStreamReader(System['in']) );
var _writer = new BufferedWriter( new OutputStreamWriter(System['out']));
......
var perf_cmd = {
invoke: function(args) {
args.shift()
var cmd = args.shift()
if (cmd in this.subcommands) {
this.subcommands[cmd].invoke(args)
} else {
this.help([])
}
},
help: function(args) {
write_string('usage:\n\n')
for (var k in this.subcommands) {
write_string(' perf ' + this.subcommands[k].usage + '\n')
}
},
list: function(args) {
write_string('available tracpoints:\n\n')
trace = Packages.com.cloudius.trace
all = trace.Tracepoint.list()
for (var i = 0; i < all.size(); ++i) {
var tp = all.get(i)
write_string(' ' + String(tp.getName()))
write_char('\n')
}
},
stat: function(args) {
var pkg = Packages.com.cloudius.trace
var counters = []
for (var i in args) {
var x = args[i]
var m = /^(([^=]+)=)?(.+)$/.exec(x)
var tag = m[2]
var name = m[3]
if (!tag) {
tag = name
}
try {
var tp = new pkg.Tracepoint(name)
var counter = new pkg.Counter(tp)
counters.push({
tag: tag,
counter: counter,
width: Math.max(8, tag.length + 2),
last: 0,
})
} catch (err) {
write_string('bad tracepoint "' + name + '"\n')
return
}
}
var titles = function() {
for (var i in counters) {
var c = counters[i]
for (var j = c.tag.length; j < c.width; ++j) {
write_string(' ')
}
write_string(c.tag)
}
write_string('\n')
}
var show = function() {
for (var i in counters) {
var ctr = counters[i]
var last = ctr.last
ctr.last = ctr.counter.read()
var delta = ctr.last - last
delta = delta.toString()
for (var j = delta.length; j < ctr.width; ++j) {
write_string(' ')
}
write_string(delta)
}
write_string('\n')
}
var line = 0
while (true) {
if (line++ % 25 == 0) {
titles()
}
show()
flush()
java.lang.Thread.sleep(1000)
}
},
subcommands: {
list: {
invoke: function(args) { this.parent.list(args) },
usage: 'list',
},
stat: {
invoke: function(args) { this.parent.stat(args) },
usage: 'stat [[tag=]tracepoint]...',
},
},
init: function() {
for (var k in this.subcommands) {
this.subcommands[k].parent = this
}
},
}
#include <osv/per-cpu-counter.hh>
#include <osv/mutex.h>
#include <debug.hh>
PERCPU(ulong*, per_cpu_counter::_counters);
namespace {
const size_t max_counters = 1000; // FIXME: allow auto-expand later
static std::vector<bool> used_indices(max_counters);
mutex mtx;
unsigned allocate_index()
{
std::lock_guard<mutex> guard{mtx};
auto i = std::find(used_indices.begin(), used_indices.end(), false);
if (i == used_indices.end()) {
abort("out of per-cpu counters");
}
*i = true;
return i - used_indices.begin();
}
void free_index(unsigned index)
{
std::lock_guard<mutex> guard{mtx};
assert(used_indices[index]);
used_indices[index] = false;
}
}
per_cpu_counter::per_cpu_counter()
: _index(allocate_index())
{
for (auto cpu : sched::cpus) {
(*_counters.for_cpu(cpu))[_index] = 0;
}
}
per_cpu_counter::~per_cpu_counter()
{
free_index(_index);
}
void per_cpu_counter::increment()
{
sched::preempt_disable();
++(*_counters)[_index];
sched::preempt_enable();
}
ulong per_cpu_counter::read()
{
ulong sum = 0;
for (auto cpu : sched::cpus) {
sum += (*_counters.for_cpu(cpu))[_index];
}
return sum;
}
void per_cpu_counter::init_on_cpu()
{
*_counters = new ulong[max_counters];
}
sched::cpu::notifier per_cpu_counter::_cpu_notifier(per_cpu_counter::init_on_cpu);
#include <osv/percpu.hh>
#include <string.h>
std::vector<void*> percpu_base{64}; // FIXME: move to sched::cpu
extern char _percpu_start[], _percpu_end[];
void percpu_init(unsigned cpu)
{
assert(!percpu_base[cpu]);
auto size = _percpu_end - _percpu_start;
percpu_base[cpu] = malloc(size);
memcpy(percpu_base[cpu], _percpu_start, size);
}
......@@ -10,6 +10,7 @@
#include "interrupt.hh"
#include "smp.hh"
#include "osv/trace.hh"
#include <osv/percpu.hh>
namespace sched {
......@@ -34,6 +35,9 @@ inter_processor_interrupt wakeup_ipi{[] {}};
constexpr u64 vruntime_bias = 4_ms;
constexpr u64 max_slice = 10_ms;
mutex cpu::notifier::_mtx;
std::list<cpu::notifier*> cpu::notifier::_notifiers __attribute__((init_priority(300)));
}
#include "arch-switch.hh"
......@@ -51,9 +55,11 @@ private:
thread _thread;
};
cpu::cpu()
: idle_thread([this] { idle(); }, thread::attr(this))
cpu::cpu(unsigned _id)
: id(_id)
, idle_thread([this] { idle(); }, thread::attr(this))
{
percpu_init(id);
}
void cpu::schedule(bool yield)
......@@ -190,6 +196,7 @@ unsigned cpu::load()
void cpu::load_balance()
{
notifier::fire();
timer tmr(*thread::current());
while (true) {
tmr.set(clock::get()->time() + 100_ms);
......@@ -225,6 +232,26 @@ void cpu::load_balance()
}
}
cpu::notifier::notifier(std::function<void ()> cpu_up)
: _cpu_up(cpu_up)
{
with_lock(_mtx, [this] { _notifiers.push_back(this); });
}
cpu::notifier::~notifier()
{
with_lock(_mtx, [this] { _notifiers.remove(this); });
}
void cpu::notifier::fire()
{
with_lock(_mtx, [] {
for (auto n : _notifiers) {
n->_cpu_up();
}
});
}
void schedule(bool yield)
{
cpu::current()->schedule(yield);
......
......@@ -4,6 +4,7 @@
#include <atomic>
#include <regex>
#include <boost/algorithm/string/replace.hpp>
#include <boost/range/algorithm/remove.hpp>
#include <debug.hh>
tracepoint<1, void*, void*> trace_function_entry("function entry", "fn %p caller %p");
......@@ -95,10 +96,23 @@ tracepoint_base::~tracepoint_base()
void tracepoint_base::enable()
{
if (enabled) {
return;
logging = true;
update();
}
void tracepoint_base::update()
{
bool new_active = logging || !probes.empty();
if (new_active && !active) {
activate();
} else if (!new_active && active) {
deactivate();
}
enabled = true;
}
void tracepoint_base::activate()
{
active = true;
for (auto& tps : tracepoint_patch_sites) {
if (id == tps.id) {
auto dst = static_cast<char*>(tps.slow_path);
......@@ -110,6 +124,28 @@ void tracepoint_base::enable()
}
}
void tracepoint_base::deactivate()
{
active = false;
for (auto& tps : tracepoint_patch_sites) {
if (id == tps.id) {
auto p = static_cast<u8*>(tps.patch_site);
// FIXME: can fail on smp.
p[0] = 0x0f;
p[1] = 0x1f;
p[2] = 0x44;
p[3] = 0x00;
p[4] = 0x00;
}
}
}
void tracepoint_base::run_probes() {
for (auto probe : probes) {
probe->hit();
}
}
void tracepoint_base::try_enable()
{
for (auto& re : enabled_tracepoint_regexs) {
......@@ -119,6 +155,21 @@ void tracepoint_base::try_enable()
}
}
void tracepoint_base::add_probe(probe* p)
{
// FIXME: locking
probes.push_back(p);
update();
}
void tracepoint_base::del_probe(probe* p)
{
// FIXME: locking
auto i = boost::remove(probes, p);
probes.erase(i, probes.end());
update();
}
std::unordered_set<tracepoint_id>& tracepoint_base::known_ids()
{
// since tracepoints are constructed in global scope, use
......
......@@ -5,6 +5,7 @@
#include "string.h"
#include "cpuid.hh"
#include "barrier.hh"
#include <osv/percpu.hh>
class kvmclock : public clock {
private:
......@@ -29,26 +30,45 @@ public:
private:
u64 wall_clock_boot();
u64 system_time();
static void setup_cpu();
private:
static bool _smp_init;
pvclock_wall_clock* _wall;
pvclock_vcpu_time_info* _sys; // FIXME: make percpu
static PERCPU(pvclock_vcpu_time_info, _sys);
sched::cpu::notifier cpu_notifier;
};
bool kvmclock::_smp_init = false;
PERCPU(kvmclock::pvclock_vcpu_time_info, kvmclock::_sys);
kvmclock::kvmclock()
: cpu_notifier(&kvmclock::setup_cpu)
{
_wall = new kvmclock::pvclock_wall_clock;
_sys = new kvmclock::pvclock_vcpu_time_info;
memset(_wall, 0, sizeof(*_wall));
memset(_sys, 0, sizeof(*_sys));
processor::wrmsr(msr::KVM_WALL_CLOCK_NEW, mmu::virt_to_phys(_wall));
// FIXME: on each cpu
processor::wrmsr(msr::KVM_SYSTEM_TIME_NEW, mmu::virt_to_phys(_sys) | 1);
}
void kvmclock::setup_cpu()
{
memset(&*_sys, 0, sizeof(*_sys));
processor::wrmsr(msr::KVM_SYSTEM_TIME_NEW, mmu::virt_to_phys(&*_sys) | 1);
_smp_init = true;
}
u64 kvmclock::time()
{
// FIXME: disable interrupts
return wall_clock_boot() + system_time();
sched::preempt_disable();
auto r = wall_clock_boot();
// Due to problems in init order dependencies (the clock depends
// on the scheduler, for percpu initialization, and vice-versa, for
// idle thread initialization, don't loop up system time until at least
// one cpu is initialized.
if (_smp_init) {
r += system_time();
}
sched::preempt_enable();
return r;
}
u64 kvmclock::wall_clock_boot()
......@@ -69,22 +89,23 @@ u64 kvmclock::system_time()
{
u32 v1, v2;
u64 time;
auto sys = &*_sys; // avoid recaclulating address each access
do {
v1 = _sys->version;
v1 = sys->version;
barrier();
time = processor::rdtsc() - _sys->tsc_timestamp;
if (_sys->tsc_shift >= 0) {
time <<= _sys->tsc_shift;
time = processor::rdtsc() - sys->tsc_timestamp;
if (sys->tsc_shift >= 0) {
time <<= sys->tsc_shift;
} else {
time >>= -_sys->tsc_shift;
time >>= -sys->tsc_shift;
}
asm("mul %1; shrd $32, %%rdx, %0"
: "+a"(time)
: "rm"(u64(_sys->tsc_to_system_mul))
: "rm"(u64(sys->tsc_to_system_mul))
: "rdx");
time += _sys->system_time;
time += sys->system_time;
barrier();
v2 = _sys->version;
v2 = sys->version;
} while (v1 != v2);
return time;
}
......
#ifndef PER_CPU_COUNTER_HH_
#define PER_CPU_COUNTER_HH_
#include <osv/types.h>
#include <sched.hh>
#include <osv/percpu.hh>
#include <sched.hh>
#include <vector>
#include <memory>
class per_cpu_counter {
public:
explicit per_cpu_counter();
~per_cpu_counter();
void increment();
ulong read();
private:
unsigned _index;
private:
static percpu<ulong*> _counters;
static sched::cpu::notifier _cpu_notifier;
static void init_on_cpu();
};
#endif /* PER_CPU_COUNTER_HH_ */
#ifndef PERCPU_HH_
#define PERCPU_HH_
#include <sched.hh>
extern char _percpu_start[];
extern std::vector<void*> percpu_base; // FIXME: move to sched::cpu
template <typename T>
class percpu {
public:
constexpr percpu() {}
T* operator->() {
return for_cpu(sched::cpu::current());
}
T& operator*() {
return *addr(sched::cpu::current());
}
T* for_cpu(sched::cpu* cpu) {
return addr(cpu);
}
private:
T *addr(sched::cpu* cpu) {
void* base = percpu_base[cpu->id];
size_t offset = reinterpret_cast<char*>(&_var) - _percpu_start;
return reinterpret_cast<T*>(base + offset);
}
private:
T _var;
};
#define PERCPU(type, var) percpu<type> var __attribute__((section(".percpu")))
void percpu_init(unsigned cpu);
#endif /* PERCPU_HH_ */
......@@ -210,16 +210,22 @@ struct serializer<N, N, args...> {
typedef std::tuple<const std::type_info*, unsigned long> tracepoint_id;
class tracepoint_base {
public:
struct probe {
virtual ~probe() {}
virtual void hit() = 0;
};
public:
explicit tracepoint_base(unsigned _id, const std::type_info& _tp_type,
const char* _name, const char* _format);
~tracepoint_base();
void enable();
void add_probe(probe* p);
void del_probe(probe* p);
tracepoint_id id;
const char* name;
const char* format;
u64 sig;
bool enabled = false;
typedef boost::intrusive::list_member_hook<> tp_list_link_type;
tp_list_link_type tp_list_link;
static boost::intrusive::list<
......@@ -229,8 +235,16 @@ public:
&tracepoint_base::tp_list_link>,
boost::intrusive::constant_time_size<false>
> tp_list;
protected:
bool active = false; // logging || !probes.empty()
bool logging = false;
std::vector<probe*> probes;
void run_probes();
private:
void try_enable();
void activate();
void deactivate();
void update();
static std::unordered_set<tracepoint_id>& known_ids();
};
......@@ -267,22 +281,30 @@ public:
trace_slow_path(assign(as...));
}
void trace_slow_path(std::tuple<s_args...> as) __attribute__((cold)) {
if (enabled) {
if (active) {
arch::irq_flag_notrace irq;
irq.save();
arch::irq_disable_notrace();
auto tr = allocate_trace_record(size());
tr->tp = this;
tr->thread = sched::thread::current();
tr->time = clock::get()->time();
tr->cpu = -1;
if (tr->thread) {
tr->cpu = tr->thread->tcpu()->id;
}
serialize(tr->buffer, as);
#undef log
log(as);
run_probes();
irq.restore();
}
}
void log(const std::tuple<s_args...>& as) {
if (!logging) {
return;
}
auto tr = allocate_trace_record(size());
tr->tp = this;
tr->thread = sched::thread::current();
tr->time = clock::get()->time();
tr->cpu = -1;
if (tr->thread) {
tr->cpu = tr->thread->tcpu()->id;
}
serialize(tr->buffer, as);
}
void serialize(void* buffer, std::tuple<s_args...> as) {
return serializer<0, sizeof...(s_args), s_args...>::write(buffer, 0, as);
}
......
......@@ -12,6 +12,7 @@
#include <osv/mutex.h>
#include <atomic>
#include "osv/lockless-queue.hh"
#include <list>
extern "C" {
void smp_main();
......@@ -273,7 +274,7 @@ typedef bi::rbtree<thread,
> runqueue_type;
struct cpu {
explicit cpu();
explicit cpu(unsigned id);
unsigned id;
struct arch_cpu arch;
thread* bringup_thread;
......@@ -294,6 +295,20 @@ struct cpu {
unsigned load();
void reschedule_from_interrupt(bool preempt = false);
void enqueue(thread& t, u64 now);
class notifier;
};
class cpu::notifier {
public:
explicit notifier(std::function<void ()> cpu_up);
~notifier();
private:
static void fire();
private:
std::function<void ()> _cpu_up;
static mutex _mtx;
static std::list<notifier*> _notifiers;
friend class cpu;
};
void preempt();
......
package com.cloudius.trace;
import java.io.Closeable;
import java.io.IOException;
public class Counter implements Closeable {
private long handle;
public Counter(Tracepoint tp) {
handle = tp.createCounter();
}
public long read() {
return Tracepoint.readCounter(handle);
}
@Override
public void finalize() {
try {
close();
} catch (IOException e) {
// nothing we can do.
}
}
@Override
public void close() throws IOException {
if (handle != 0) {
Tracepoint.destroyCounter(handle);
handle = 0;
}
}
}
package com.cloudius.trace;
import com.cloudius.*;
import java.util.*;
public class Tracepoint {
static {
Config.loadJNI("tracepoint.so");
}
private String name;
private long handle;
Tracepoint(long handle) {
this.handle = handle;
}
public Tracepoint(String name) {
this.handle = findByName(name);
}
public String getName() {
return doGetName(handle);
}
public void enable() {
doEnable(handle);
}
public static List<Tracepoint> list() {
long[] handles = doList();
System.out.flush();
List<Tracepoint> ret = new ArrayList<Tracepoint>(handles.length);
for (long handle : handles) {
ret.add(new Tracepoint(handle));
}
return ret;
}
long createCounter() {
return doCreateCounter(handle);
}
native static long[] doList();
native static long findByName(String name);
native static void doEnable(long handle);
native static String doGetName(long handle);
native static long doCreateCounter(long handle);
native static void destroyCounter(long handle);
native static long readCounter(long handle);
}
#include "tracepoint.hh"
#include <osv/trace.hh>
#include <osv/per-cpu-counter.hh>
#include <debug.hh>
static std::string get_string(JNIEnv* jni, jstring s)
{
auto p = jni->GetStringUTFChars(s, nullptr);
std::string ret(p);
jni->ReleaseStringUTFChars(s, p);
return ret;
}
JNIEXPORT jlongArray JNICALL Java_com_cloudius_trace_Tracepoint_doList
(JNIEnv *jni, jclass klass)
{
auto nr = tracepoint_base::tp_list.size();
auto a = jni->NewLongArray(nr);
size_t idx = 0;
for (auto& tp : tracepoint_base::tp_list) {
jlong handle = jlong(reinterpret_cast<uintptr_t>(&tp));
jni->SetLongArrayRegion(a, idx++, 1, &handle);
};
return a;
}
JNIEXPORT jlong JNICALL Java_com_cloudius_trace_Tracepoint_findByName
(JNIEnv *jni, jclass klass, jstring name)
{
auto n = get_string(jni, name);
for (auto& tp : tracepoint_base::tp_list) {
if (n == tp.name) {
return reinterpret_cast<uintptr_t>(&tp);
}
}
auto re = jni->FindClass("java/lang/RuntimeException");
jni->ThrowNew(re, "Cannot find tracepoint");
return 0;
}
JNIEXPORT void JNICALL Java_com_cloudius_trace_Tracepoint_doEnable
(JNIEnv *jni, jclass klass, jlong handle)
{
auto tp = reinterpret_cast<tracepoint_base*>(handle);
tp->enable();
}
JNIEXPORT jstring JNICALL Java_com_cloudius_trace_Tracepoint_doGetName
(JNIEnv *jni, jclass klass, jlong handle)
{
auto tp = reinterpret_cast<tracepoint_base*>(handle);
return jni->NewStringUTF(tp->name);
}
class tracepoint_counter : public tracepoint_base::probe {
public:
explicit tracepoint_counter(tracepoint_base& tp) : _tp(tp) {
_tp.add_probe(this);
}
virtual ~tracepoint_counter() { _tp.del_probe(this); }
virtual void hit() { _counter.increment(); }
ulong read() { return _counter.read(); }
private:
tracepoint_base& _tp;
per_cpu_counter _counter;
};
JNIEXPORT jlong JNICALL Java_com_cloudius_trace_Tracepoint_doCreateCounter
(JNIEnv *jni, jclass klass, jlong handle)
{
auto tp = reinterpret_cast<tracepoint_base*>(handle);
auto c = new tracepoint_counter(*tp);
return reinterpret_cast<jlong>(c);
}
JNIEXPORT void JNICALL Java_com_cloudius_trace_Tracepoint_destroyCounter
(JNIEnv *jni, jclass klazz, jlong handle)
{
auto c = reinterpret_cast<tracepoint_counter*>(handle);
delete c;
}
JNIEXPORT jlong JNICALL Java_com_cloudius_trace_Tracepoint_readCounter
(JNIEnv *jni, jclass klass, jlong handle)
{
auto c = reinterpret_cast<tracepoint_counter*>(handle);
return c->read();
}
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_cloudius_trace_Tracepoint */
#ifndef _Included_com_cloudius_trace_Tracepoint
#define _Included_com_cloudius_trace_Tracepoint
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_cloudius_trace_Tracepoint
* Method: doList
* Signature: ()[J
*/
JNIEXPORT jlongArray JNICALL Java_com_cloudius_trace_Tracepoint_doList
(JNIEnv *, jclass);
/*
* Class: com_cloudius_trace_Tracepoint
* Method: findByName
* Signature: (Ljava/lang/String;)J
*/
JNIEXPORT jlong JNICALL Java_com_cloudius_trace_Tracepoint_findByName
(JNIEnv *, jclass, jstring);
/*
* Class: com_cloudius_trace_Tracepoint
* Method: doEnable
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_com_cloudius_trace_Tracepoint_doEnable
(JNIEnv *, jclass, jlong);
/*
* Class: com_cloudius_trace_Tracepoint
* Method: doGetName
* Signature: (J)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_cloudius_trace_Tracepoint_doGetName
(JNIEnv *, jclass, jlong);
/*
* Class: com_cloudius_trace_Tracepoint
* Method: doCreateCounter
* Signature: (J)J
*/
JNIEXPORT jlong JNICALL Java_com_cloudius_trace_Tracepoint_doCreateCounter
(JNIEnv *, jclass, jlong);
/*
* Class: com_cloudius_trace_Tracepoint
* Method: destroyCounter
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_com_cloudius_trace_Tracepoint_destroyCounter
(JNIEnv *, jclass, jlong);
/*
* Class: com_cloudius_trace_Tracepoint
* Method: readCounter
* Signature: (J)J
*/
JNIEXPORT jlong JNICALL Java_com_cloudius_trace_Tracepoint_readCounter
(JNIEnv *, jclass, jlong);
#ifdef __cplusplus
}
#endif
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment