blob: ad4b43c27d1230daf80b935e5932d7b3f5e168a0 [file] [log] [blame]
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <sys/time.h>
#include <time.h>
#include <errno.h>
#include <stdio.h>
#include "hprof.h"
#include "stringprintf.h"
#include "logging.h"
namespace art {
namespace hprof {
int HprofRecord::Flush(FILE *fp) {
if (dirty_) {
unsigned char headBuf[sizeof (uint8_t) + 2 * sizeof (uint32_t)];
headBuf[0] = tag_;
U4_TO_BUF_BE(headBuf, 1, time_);
U4_TO_BUF_BE(headBuf, 5, length_);
int nb = fwrite(headBuf, 1, sizeof(headBuf), fp);
if (nb != sizeof(headBuf)) {
return UNIQUE_ERROR();
}
nb = fwrite(body_, 1, length_, fp);
if (nb != (int)length_) {
return UNIQUE_ERROR();
}
dirty_ = false;
}
// TODO if we used less than half (or whatever) of allocLen, shrink the buffer.
return 0;
}
int HprofRecord::GuaranteeRecordAppend(size_t nmore) {
size_t minSize = length_ + nmore;
if (minSize > alloc_length_) {
size_t newAllocLen = alloc_length_ * 2;
if (newAllocLen < minSize) {
newAllocLen = alloc_length_ + nmore + nmore/2;
}
unsigned char* newBody = (unsigned char*)realloc(body_, newAllocLen);
if (newBody != NULL) {
body_ = newBody;
alloc_length_ = newAllocLen;
} else {
// TODO: set an error flag so future ops will fail
return UNIQUE_ERROR();
}
}
CHECK_LE(length_ + nmore, alloc_length_);
return 0;
}
int HprofRecord::AddU1List(const uint8_t *values, size_t numValues) {
int err = GuaranteeRecordAppend(numValues);
if (err != 0) {
return err;
}
memcpy(body_ + length_, values, numValues);
length_ += numValues;
return 0;
}
int HprofRecord::AddU1(uint8_t value) {
int err = GuaranteeRecordAppend(1);
if (err != 0) {
return err;
}
body_[length_++] = value;
return 0;
}
int HprofRecord::AddUtf8String(const char* str) {
// The terminating NUL character is NOT written.
return AddU1List((const uint8_t *)str, strlen(str));
}
int HprofRecord::AddU2List(const uint16_t *values, size_t numValues) {
int err = GuaranteeRecordAppend(numValues * 2);
if (err != 0) {
return err;
}
unsigned char* insert = body_ + length_;
for (size_t i = 0; i < numValues; i++) {
U2_TO_BUF_BE(insert, 0, *values++);
insert += sizeof(*values);
}
length_ += numValues * 2;
return 0;
}
int HprofRecord::AddU2(uint16_t value) {
return AddU2List(&value, 1);
}
int HprofRecord::AddIdList(const HprofObjectId *values, size_t numValues) {
return AddU4List((const uint32_t*) values, numValues);
}
int HprofRecord::AddU4List(const uint32_t *values, size_t numValues) {
int err = GuaranteeRecordAppend(numValues * 4);
if (err != 0) {
return err;
}
unsigned char* insert = body_ + length_;
for (size_t i = 0; i < numValues; i++) {
U4_TO_BUF_BE(insert, 0, *values++);
insert += sizeof(*values);
}
length_ += numValues * 4;
return 0;
}
int HprofRecord::AddU4(uint32_t value) {
return AddU4List(&value, 1);
}
int HprofRecord::AddId(HprofObjectId value) {
return AddU4((uint32_t) value);
}
int HprofRecord::AddU8List(const uint64_t *values, size_t numValues) {
int err = GuaranteeRecordAppend(numValues * 8);
if (err != 0) {
return err;
}
unsigned char* insert = body_ + length_;
for (size_t i = 0; i < numValues; i++) {
U8_TO_BUF_BE(insert, 0, *values++);
insert += sizeof(*values);
}
length_ += numValues * 8;
return 0;
}
int HprofRecord::AddU8(uint64_t value) {
return AddU8List(&value, 1);
}
} // namespace hprof
} // namespace art