#872: Get rid of libstdc++ streams
This commit is contained in:
+2
-9
@@ -3,8 +3,6 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include "asprof.h"
|
||||
#include "hooks.h"
|
||||
#include "profiler.h"
|
||||
@@ -33,22 +31,17 @@ DLLEXPORT asprof_error_t asprof_execute(const char* command, asprof_writer_t out
|
||||
Log::open(args);
|
||||
|
||||
if (!args.hasOutputFile()) {
|
||||
// FIXME: get rid of stream
|
||||
std::ostringstream out;
|
||||
CallbackWriter out(output_callback);
|
||||
error = Profiler::instance()->runInternal(args, out);
|
||||
if (!error) {
|
||||
if (output_callback != NULL) {
|
||||
output_callback(out.str().data(), out.str().size());
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
std::ofstream out(args.file(), std::ios::out | std::ios::trunc);
|
||||
FileWriter out(args.file());
|
||||
if (!out.is_open()) {
|
||||
return asprof_error("Could not open output file");
|
||||
}
|
||||
error = Profiler::instance()->runInternal(args, out);
|
||||
out.close();
|
||||
if (!error) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+8
-6
@@ -111,7 +111,7 @@ Trie* FlameGraph::addChild(Trie* f, const char* name, FrameTypeId type, u64 valu
|
||||
}
|
||||
}
|
||||
|
||||
void FlameGraph::dump(std::ostream& out, bool tree) {
|
||||
void FlameGraph::dump(Writer& out, bool tree) {
|
||||
_name_order = new u32[_cpool.size() + 1]();
|
||||
_mintotal = _minwidth == 0 && tree ? _root._total / 1000 : (u64)(_root._total * _minwidth / 100);
|
||||
int depth = _root.depth(_mintotal, _name_order);
|
||||
@@ -167,7 +167,7 @@ void FlameGraph::dump(std::ostream& out, bool tree) {
|
||||
delete[] _name_order;
|
||||
}
|
||||
|
||||
void FlameGraph::printFrame(std::ostream& out, u32 key, const Trie& f, int level, u64 x) {
|
||||
void FlameGraph::printFrame(Writer& out, u32 key, const Trie& f, int level, u64 x) {
|
||||
u32 name_and_type = _name_order[f.nameIndex(key)] << 3 | f.type(key);
|
||||
bool has_extra_types = (f._inlined | f._c1_compiled | f._interpreted) &&
|
||||
f._inlined < f._total && f._interpreted < f._total;
|
||||
@@ -217,7 +217,7 @@ void FlameGraph::printFrame(std::ostream& out, u32 key, const Trie& f, int level
|
||||
}
|
||||
}
|
||||
|
||||
void FlameGraph::printTreeFrame(std::ostream& out, const Trie& f, int level, const char** names) {
|
||||
void FlameGraph::printTreeFrame(Writer& out, const Trie& f, int level, const char** names) {
|
||||
std::vector<Node> children;
|
||||
children.reserve(f._children.size());
|
||||
for (std::map<u32, Trie>::const_iterator it = f._children.begin(); it != f._children.end(); ++it) {
|
||||
@@ -264,7 +264,7 @@ void FlameGraph::printTreeFrame(std::ostream& out, const Trie& f, int level, con
|
||||
}
|
||||
}
|
||||
|
||||
void FlameGraph::printCpool(std::ostream& out) {
|
||||
void FlameGraph::printCpool(Writer& out) {
|
||||
out << "'all'";
|
||||
|
||||
std::string prev;
|
||||
@@ -282,7 +282,9 @@ void FlameGraph::printCpool(std::ostream& out) {
|
||||
|
||||
StringUtils::replace(s, '\\', "\\\\", 2);
|
||||
StringUtils::replace(s, '\'', "\\'", 2);
|
||||
out << ",\n'" << s << "'";
|
||||
out << ",\n'";
|
||||
out.write(s.data(), s.size());
|
||||
out << "'";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,7 +292,7 @@ void FlameGraph::printCpool(std::ostream& out) {
|
||||
_cpool = std::map<std::string, u32>();
|
||||
}
|
||||
|
||||
const char* FlameGraph::printTill(std::ostream& out, const char* data, const char* till) {
|
||||
const char* FlameGraph::printTill(Writer& out, const char* data, const char* till) {
|
||||
const char* pos = strstr(data, till);
|
||||
out.write(data, pos - data);
|
||||
return pos + strlen(till);
|
||||
|
||||
+6
-6
@@ -6,12 +6,12 @@
|
||||
#ifndef _FLAMEGRAPH_H
|
||||
#define _FLAMEGRAPH_H
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include "arch.h"
|
||||
#include "arguments.h"
|
||||
#include "vmEntry.h"
|
||||
#include "writer.h"
|
||||
|
||||
|
||||
class Trie {
|
||||
@@ -75,10 +75,10 @@ class FlameGraph {
|
||||
u64 _last_x;
|
||||
u64 _last_total;
|
||||
|
||||
void printFrame(std::ostream& out, u32 key, const Trie& f, int level, u64 x);
|
||||
void printTreeFrame(std::ostream& out, const Trie& f, int level, const char** names);
|
||||
void printCpool(std::ostream& out);
|
||||
const char* printTill(std::ostream& out, const char* data, const char* till);
|
||||
void printFrame(Writer& out, u32 key, const Trie& f, int level, u64 x);
|
||||
void printTreeFrame(Writer& out, const Trie& f, int level, const char** names);
|
||||
void printCpool(Writer& out);
|
||||
const char* printTill(Writer& out, const char* data, const char* till);
|
||||
|
||||
public:
|
||||
FlameGraph(const char* title, Counter counter, double minwidth, bool reverse) :
|
||||
@@ -100,7 +100,7 @@ class FlameGraph {
|
||||
|
||||
Trie* addChild(Trie* f, const char* name, FrameTypeId type, u64 value);
|
||||
|
||||
void dump(std::ostream& out, bool tree);
|
||||
void dump(Writer& out, bool tree);
|
||||
};
|
||||
|
||||
#endif // _FLAMEGRAPH_H
|
||||
|
||||
+5
-7
@@ -3,8 +3,6 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "asprof.h"
|
||||
@@ -71,23 +69,23 @@ Java_one_profiler_AsyncProfiler_execute0(JNIEnv* env, jobject unused, jstring co
|
||||
Log::open(args);
|
||||
|
||||
if (!args.hasOutputFile()) {
|
||||
std::ostringstream out;
|
||||
BufferWriter out;
|
||||
error = Profiler::instance()->runInternal(args, out);
|
||||
if (!error) {
|
||||
if (out.tellp() >= 0x3fffffff) {
|
||||
out << '\0';
|
||||
if (out.size() >= 0x3fffffff) {
|
||||
throwNew(env, "java/lang/IllegalStateException", "Output exceeds string size limit");
|
||||
return NULL;
|
||||
}
|
||||
return env->NewStringUTF(out.str().c_str());
|
||||
return env->NewStringUTF(out.buf());
|
||||
}
|
||||
} else {
|
||||
std::ofstream out(args.file(), std::ios::out | std::ios::trunc);
|
||||
FileWriter out(args.file());
|
||||
if (!out.is_open()) {
|
||||
throwNew(env, "java/io/IOException", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
error = Profiler::instance()->runInternal(args, out);
|
||||
out.close();
|
||||
if (!error) {
|
||||
return env->NewStringUTF("OK");
|
||||
}
|
||||
|
||||
+11
-15
@@ -4,7 +4,6 @@
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <dlfcn.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
@@ -1295,7 +1294,7 @@ Error Profiler::flushJfr() {
|
||||
return Error::OK;
|
||||
}
|
||||
|
||||
Error Profiler::dump(std::ostream& out, Arguments& args) {
|
||||
Error Profiler::dump(Writer& out, Arguments& args) {
|
||||
MutexLocker ml(_state_lock);
|
||||
if (_state != IDLE && _state != RUNNING) {
|
||||
return Error("Profiler has not started");
|
||||
@@ -1333,7 +1332,7 @@ Error Profiler::dump(std::ostream& out, Arguments& args) {
|
||||
return Error::OK;
|
||||
}
|
||||
|
||||
void Profiler::printUsedMemory(std::ostream& out) {
|
||||
void Profiler::printUsedMemory(Writer& out) {
|
||||
size_t call_trace_storage = _call_trace_storage.usedMemory();
|
||||
size_t dictionaries = _class_map.usedMemory() + _symbol_map.usedMemory() + _thread_filter.usedMemory() + _jfr.usedMemory();
|
||||
|
||||
@@ -1379,7 +1378,7 @@ void Profiler::switchThreadEvents(jvmtiEventMode mode) {
|
||||
*
|
||||
* <frame>;<frame>;...;<topmost frame> <count>
|
||||
*/
|
||||
void Profiler::dumpCollapsed(std::ostream& out, Arguments& args) {
|
||||
void Profiler::dumpCollapsed(Writer& out, Arguments& args) {
|
||||
FrameName fn(args, args._style | STYLE_NO_SEMICOLON, _epoch, _thread_names_lock, _thread_names);
|
||||
char buf[32];
|
||||
|
||||
@@ -1406,7 +1405,7 @@ void Profiler::dumpCollapsed(std::ostream& out, Arguments& args) {
|
||||
}
|
||||
}
|
||||
|
||||
void Profiler::dumpFlameGraph(std::ostream& out, Arguments& args, bool tree) {
|
||||
void Profiler::dumpFlameGraph(Writer& out, Arguments& args, bool tree) {
|
||||
char title[64];
|
||||
if (args._title == NULL) {
|
||||
Engine* active_engine = activeEngine();
|
||||
@@ -1466,7 +1465,7 @@ void Profiler::dumpFlameGraph(std::ostream& out, Arguments& args, bool tree) {
|
||||
flamegraph.dump(out, tree);
|
||||
}
|
||||
|
||||
void Profiler::dumpText(std::ostream& out, Arguments& args) {
|
||||
void Profiler::dumpText(Writer& out, Arguments& args) {
|
||||
FrameName fn(args, args._style | STYLE_DOTTED, _epoch, _thread_names_lock, _thread_names);
|
||||
char buf[1024] = {0};
|
||||
|
||||
@@ -1656,7 +1655,7 @@ void Profiler::timerLoop(void* timer_id) {
|
||||
}
|
||||
}
|
||||
|
||||
Error Profiler::runInternal(Arguments& args, std::ostream& out) {
|
||||
Error Profiler::runInternal(Arguments& args, Writer& out) {
|
||||
switch (args._action) {
|
||||
case ACTION_START:
|
||||
case ACTION_RESUME: {
|
||||
@@ -1734,7 +1733,6 @@ Error Profiler::runInternal(Arguments& args, std::ostream& out) {
|
||||
}
|
||||
case ACTION_VERSION:
|
||||
out << PROFILER_VERSION;
|
||||
out.flush();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -1744,17 +1742,16 @@ Error Profiler::runInternal(Arguments& args, std::ostream& out) {
|
||||
|
||||
Error Profiler::run(Arguments& args) {
|
||||
if (!args.hasOutputFile()) {
|
||||
return runInternal(args, std::cout);
|
||||
FileWriter out(STDOUT_FILENO);
|
||||
return runInternal(args, out);
|
||||
} else {
|
||||
// Open output file under the lock to avoid races with background timer
|
||||
MutexLocker ml(_state_lock);
|
||||
std::ofstream out(args.file(), std::ios::out | std::ios::trunc);
|
||||
FileWriter out(args.file());
|
||||
if (!out.is_open()) {
|
||||
return Error("Could not open output file");
|
||||
}
|
||||
Error error = runInternal(args, out);
|
||||
out.close();
|
||||
return error;
|
||||
return runInternal(args, out);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1767,12 +1764,11 @@ Error Profiler::restart(Arguments& args) {
|
||||
}
|
||||
|
||||
if (args._file != NULL && args._output != OUTPUT_NONE && args._output != OUTPUT_JFR) {
|
||||
std::ofstream out(args.file(), std::ios::out | std::ios::trunc);
|
||||
FileWriter out(args.file());
|
||||
if (!out.is_open()) {
|
||||
return Error("Could not open output file");
|
||||
}
|
||||
error = dump(out, args);
|
||||
out.close();
|
||||
if (error) {
|
||||
return error;
|
||||
}
|
||||
|
||||
+8
-7
@@ -6,8 +6,8 @@
|
||||
#ifndef _PROFILER_H
|
||||
#define _PROFILER_H
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <time.h>
|
||||
#include "arch.h"
|
||||
#include "arguments.h"
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "threadFilter.h"
|
||||
#include "trap.h"
|
||||
#include "vmEntry.h"
|
||||
#include "writer.h"
|
||||
|
||||
|
||||
const int MAX_NATIVE_FRAMES = 128;
|
||||
@@ -145,9 +146,9 @@ class Profiler {
|
||||
void lockAll();
|
||||
void unlockAll();
|
||||
|
||||
void dumpCollapsed(std::ostream& out, Arguments& args);
|
||||
void dumpFlameGraph(std::ostream& out, Arguments& args, bool tree);
|
||||
void dumpText(std::ostream& out, Arguments& args);
|
||||
void dumpCollapsed(Writer& out, Arguments& args);
|
||||
void dumpFlameGraph(Writer& out, Arguments& args, bool tree);
|
||||
void dumpText(Writer& out, Arguments& args);
|
||||
|
||||
static Profiler* const _instance;
|
||||
|
||||
@@ -189,15 +190,15 @@ class Profiler {
|
||||
CodeCacheArray* nativeLibs() { return &_native_libs; }
|
||||
|
||||
Error run(Arguments& args);
|
||||
Error runInternal(Arguments& args, std::ostream& out);
|
||||
Error runInternal(Arguments& args, Writer& out);
|
||||
Error restart(Arguments& args);
|
||||
void shutdown(Arguments& args);
|
||||
Error check(Arguments& args);
|
||||
Error start(Arguments& args, bool reset);
|
||||
Error stop(bool restart = false);
|
||||
Error flushJfr();
|
||||
Error dump(std::ostream& out, Arguments& args);
|
||||
void printUsedMemory(std::ostream& out);
|
||||
Error dump(Writer& out, Arguments& args);
|
||||
void printUsedMemory(Writer& out);
|
||||
void switchThreadEvents(jvmtiEventMode mode);
|
||||
int convertNativeTrace(int native_frames, const void** callchain, ASGCT_CallFrame* frames);
|
||||
u64 recordSample(void* ucontext, u64 counter, EventType event_type, Event* event);
|
||||
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright The async-profiler authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "writer.h"
|
||||
|
||||
|
||||
Writer& Writer::operator<<(char c) {
|
||||
write(&c, 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Writer& Writer::operator<<(const char* s) {
|
||||
write(s, strlen(s));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Writer& Writer::operator<<(int n) {
|
||||
char buf[16];
|
||||
write(buf, snprintf(buf, sizeof(buf), "%d", n));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Writer& Writer::operator<<(long n) {
|
||||
char buf[24];
|
||||
write(buf, snprintf(buf, sizeof(buf), "%ld", n));
|
||||
return *this;
|
||||
}
|
||||
|
||||
FileWriter::FileWriter(const char* file_name) : _size(0) {
|
||||
_fd = open(file_name, O_WRONLY | O_TRUNC | O_CREAT, 0644);
|
||||
_buf = (char*)malloc(BUF_SIZE);
|
||||
}
|
||||
|
||||
FileWriter::FileWriter(int fd) : _fd(fd), _size(0) {
|
||||
_buf = (char*)malloc(BUF_SIZE);
|
||||
}
|
||||
|
||||
FileWriter::~FileWriter() {
|
||||
flush(_buf, _size);
|
||||
free(_buf);
|
||||
if (_fd > STDERR_FILENO) {
|
||||
close(_fd);
|
||||
}
|
||||
}
|
||||
|
||||
void FileWriter::flush(const char* data, size_t len) {
|
||||
while (len > 0) {
|
||||
ssize_t bytes = ::write(_fd, data, len);
|
||||
if (bytes < 0) {
|
||||
_err = errno;
|
||||
break;
|
||||
}
|
||||
data += bytes;
|
||||
len -= (size_t)bytes;
|
||||
}
|
||||
}
|
||||
|
||||
void FileWriter::write(const char* data, size_t len) {
|
||||
if (_size + len > BUF_SIZE) {
|
||||
flush(_buf, _size);
|
||||
_size = 0;
|
||||
if (len > BUF_SIZE) {
|
||||
flush(data, len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
memcpy(_buf + _size, data, len);
|
||||
_size += len;
|
||||
}
|
||||
|
||||
BufferWriter::BufferWriter(size_t capacity) : _size(0), _capacity(capacity) {
|
||||
_buf = (char*)malloc(capacity);
|
||||
}
|
||||
|
||||
BufferWriter::~BufferWriter() {
|
||||
free(_buf);
|
||||
}
|
||||
|
||||
void BufferWriter::write(const char* data, size_t len) {
|
||||
size_t new_size = _size + len;
|
||||
if (new_size > _capacity) {
|
||||
_capacity = new_size >= _capacity * 2 ? new_size : _capacity * 2;
|
||||
_buf = (char*)realloc(_buf, _capacity);
|
||||
}
|
||||
memcpy(_buf + _size, data, len);
|
||||
_size = new_size;
|
||||
}
|
||||
|
||||
void CallbackWriter::write(const char* data, size_t len) {
|
||||
if (_output_callback != NULL) {
|
||||
_output_callback(data, len);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright The async-profiler authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _WRITER_H
|
||||
#define _WRITER_H
|
||||
|
||||
#include "asprof.h"
|
||||
|
||||
|
||||
class Writer {
|
||||
protected:
|
||||
int _err;
|
||||
|
||||
Writer() : _err(0) {
|
||||
}
|
||||
|
||||
public:
|
||||
Writer& operator<<(char c);
|
||||
Writer& operator<<(const char* s);
|
||||
Writer& operator<<(int n);
|
||||
Writer& operator<<(long n);
|
||||
|
||||
bool good() const {
|
||||
return _err == 0;
|
||||
}
|
||||
|
||||
virtual void write(const char* data, size_t len) = 0;
|
||||
};
|
||||
|
||||
class FileWriter : public Writer {
|
||||
private:
|
||||
int _fd;
|
||||
char* _buf;
|
||||
size_t _size;
|
||||
|
||||
enum { BUF_SIZE = 8192 };
|
||||
|
||||
void flush(const char* data, size_t len);
|
||||
|
||||
public:
|
||||
FileWriter(const char* file_name);
|
||||
FileWriter(int fd);
|
||||
~FileWriter();
|
||||
|
||||
bool is_open() const {
|
||||
return _fd >= 0;
|
||||
}
|
||||
|
||||
virtual void write(const char* data, size_t len);
|
||||
};
|
||||
|
||||
class BufferWriter : public Writer {
|
||||
private:
|
||||
char* _buf;
|
||||
size_t _size;
|
||||
size_t _capacity;
|
||||
|
||||
public:
|
||||
BufferWriter(size_t capacity = 256);
|
||||
~BufferWriter();
|
||||
|
||||
char* buf() const {
|
||||
return _buf;
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
virtual void write(const char* data, size_t len);
|
||||
};
|
||||
|
||||
class CallbackWriter : public Writer {
|
||||
private:
|
||||
asprof_writer_t _output_callback;
|
||||
|
||||
public:
|
||||
CallbackWriter(asprof_writer_t output_callback) : _output_callback(output_callback) {
|
||||
}
|
||||
|
||||
virtual void write(const char* data, size_t len);
|
||||
};
|
||||
|
||||
#endif // _WRITER_H
|
||||
Reference in New Issue
Block a user