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

test softcounter #46

Merged
merged 9 commits into from
Jan 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/basic-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ jobs:

- name: Build TypeART
run: |
cmake -B build -DTEST_CONFIG=ON -DENABLE_CODE_COVERAGE=ON -DLLVM_EXTERNAL_LIT=${EXTERNAL_LIT}
cmake -B build -DTEST_CONFIG=ON -DENABLE_CODE_COVERAGE=ON -DSOFTCOUNTERS=ON -DLLVM_EXTERNAL_LIT=${EXTERNAL_LIT}
cmake --build build --parallel

- name: Test TypeART with coverage (exludes lulesh)
- name: Test TypeART with coverage
run: |
cmake --build build --target lcov-clean
cmake --build build --target test -- ARGS=-VV
Expand All @@ -51,7 +51,7 @@ jobs:

- name: Build TypeART release
run: |
cmake -B build_lulesh -DCMAKE_BUILD_TYPE=Release -DMPI_INTERCEPT_LIB=ON -DSHOW_STATS=ON
cmake -B build_lulesh -DCMAKE_BUILD_TYPE=Release -DMPI_INTERCEPT_LIB=ON -DSHOW_STATS=ON -DSOFTCOUNTERS=ON
cmake --build build_lulesh --parallel

- name: Test TypeART release on lulesh
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ext-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:

- name: Build & install TypeART
run: |
cmake -B build -DCMAKE_BUILD_TYPE=Release -DMPI_INTERCEPT_LIB=ON -DSHOW_STATS=ON
cmake -B build -DCMAKE_BUILD_TYPE=Release -DMPI_INTERCEPT_LIB=ON -DSHOW_STATS=ON -DSOFTCOUNTERS=ON
cmake --build build --parallel --target install
echo "TYPEART_PATH=${GITHUB_WORKSPACE}/install/typeart" >> $GITHUB_ENV

Expand Down
2 changes: 2 additions & 0 deletions cmake/ToolchainOptions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ option(SOFTCOUNTERS "Enable software tracking of #tracked addrs. / #distinct che
option(TEST_CONFIG "Set logging levels to appropriate levels for test runner to succeed" OFF)
option(ENABLE_CODE_COVERAGE "Enable code coverage statistics" OFF)
option(ENABLE_LLVM_CODE_COVERAGE "Enable llvm-cov code coverage statistics" OFF)
option(TEST_CONFIGURE_IDE "Add targets so the IDE (e.g., Clion) can interpret test files better" ON)
mark_as_advanced(TEST_CONFIGURE_IDE)

include(AddLLVM)
include(llvm-lit)
Expand Down
114 changes: 114 additions & 0 deletions lib/runtime/AccessCountPrinter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//
// Created by ahueck on 30.12.20.
//

#ifndef TYPEART_ACCESSCOUNTPRINTER_H
#define TYPEART_ACCESSCOUNTPRINTER_H

#include "AccessCounter.h"
#include "support/Logger.h"
#include "support/Table.h"

#include <map>
#include <set>
#include <sstream>
#include <string>
#include <string_view>
#include <unordered_map>
#include <unordered_set>

namespace typeart::softcounter {
namespace memory {
struct MemOverhead {
static constexpr auto pointerMapSize = sizeof(RuntimeT::PointerMap); // Map overhead
static constexpr auto perNodeSizeMap =
sizeof(std::remove_pointer<std::map<MemAddr, PointerInfo>::iterator::_Link_type>::type) +
sizeof(RuntimeT::MapEntry); // not applicable to btree
static constexpr auto stackVectorSize = sizeof(RuntimeT::Stack); // Stack overhead
static constexpr auto perNodeSizeStack = sizeof(RuntimeT::StackEntry); // Stack allocs
double stack{0};
double map{0};
};
inline MemOverhead estimate(Counter stack_max, Counter heap_max, Counter global_max, const double scale = 1024.0) {
MemOverhead mem;
mem.stack = double(MemOverhead::stackVectorSize +
MemOverhead::perNodeSizeStack * std::max<size_t>(RuntimeT::StackReserve, stack_max)) /
scale;
mem.map =
double(MemOverhead::pointerMapSize + MemOverhead::perNodeSizeMap * (stack_max + heap_max + global_max)) / scale;
return mem;
}
} // namespace memory

template <typename Recorder>
void serialise(const Recorder& r, llvm::raw_ostream& buf) {
if constexpr (std::is_same_v<Recorder, NoneRecorder>) {
return;
} else {
const auto memory_use = memory::estimate(r.getMaxStackAllocs(), r.getMaxHeapAllocs(), r.getGlobalAllocs());

Table t("Alloc Stats from softcounters");
t.wrap_length = true;
t.put(Row::make("Total heap", r.getHeapAllocs(), r.getHeapArray()));
t.put(Row::make("Total stack", r.getStackAllocs(), r.getStackArray()));
t.put(Row::make("Total global", r.getGlobalAllocs(), r.getGlobalArray()));
t.put(Row::make("Max. Heap Allocs", r.getMaxHeapAllocs()));
t.put(Row::make("Max. Stack Allocs", r.getMaxStackAllocs()));
t.put(Row::make("Addresses checked", r.getAddrChecked()));
t.put(Row::make("Distinct Addresses checked", r.getSeen().size()));
t.put(Row::make("Addresses re-used", r.getAddrReuses()));
t.put(Row::make("Addresses missed", r.getAddrMissing()));
t.put(Row::make("Distinct Addresses missed", r.getMissing().size()));
t.put(Row::make("Total free heap", r.getHeapAllocsFree(), r.getHeapArrayFree()));
t.put(Row::make("Total free stack", r.getStackAllocsFree(), r.getStackArrayFree()));
t.put(Row::make("Null/Zero/NullZero Addr", r.getNullAlloc(), r.getZeroAlloc(), r.getNullAndZeroAlloc()));
t.put(Row::make("User-def. types", r.getNumUDefTypes()));
t.put(Row::make("Estimated memory use (KiB)", size_t(std::round(memory_use.map + memory_use.stack))));
t.put(Row::make("Bytes per node map/stack", memory::MemOverhead::perNodeSizeMap,
memory::MemOverhead::perNodeSizeStack));

t.print(buf);

std::set<int> type_id_set;
const auto fill_set = [&type_id_set](const auto& map) {
for (const auto& [key, val] : map) {
type_id_set.insert(key);
}
};
fill_set(r.getHeapAlloc());
fill_set(r.getGlobalAlloc());
fill_set(r.getStackAlloc());
fill_set(r.getHeapFree());
fill_set(r.getStackFree());

const auto count = [](const auto& map, auto id) {
auto it = map.find(id);
if (it != map.end()) {
return it->second;
}
return 0ll;
};

Table type_table("Allocation type detail (heap, stack, global)");
type_table.table_header = '#';
for (auto type_id : type_id_set) {
type_table.put(Row::make(std::to_string(type_id), count(r.getHeapAlloc(), type_id),
count(r.getStackAlloc(), type_id), count(r.getGlobalAlloc(), type_id),
typeart_get_type_name(type_id)));
}

type_table.print(buf);

Table type_table_free("Free allocation type detail (heap, stack)");
type_table_free.table_header = '#';
for (auto type_id : type_id_set) {
type_table_free.put(Row::make(std::to_string(type_id), count(r.getHeapFree(), type_id),
count(r.getStackFree(), type_id), typeart_get_type_name(type_id)));
}

type_table_free.print(buf);
}
}
} // namespace typeart::softcounter

#endif // TYPEART_ACCESSCOUNTPRINTER_H
195 changes: 96 additions & 99 deletions lib/runtime/AccessCounter.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@

#include "RuntimeData.h"
#include "RuntimeInterface.h"
#include "support/Logger.h"
#include "support/Table.h"

#include <map>
#include <set>
Expand All @@ -31,6 +29,13 @@ class AccessRecorder {

inline void incHeapAlloc(int typeId, size_t count) {
++curHeapAllocs;

// Always check here for max
// A program without free would otherwise never update maxHeap (see test 20_softcounter_max)
if (curHeapAllocs > maxHeapAllocs) {
maxHeapAllocs = curHeapAllocs;
}

++heapAllocs;
if (count > 1) {
++heapArray;
Expand Down Expand Up @@ -72,9 +77,10 @@ class AccessRecorder {
}

inline void decHeapAlloc() {
if (curHeapAllocs > maxHeapAllocs) {
maxHeapAllocs = curHeapAllocs;
}
// Removed, since we already increment maxHeapAllocs just in time:
// if (curHeapAllocs > maxHeapAllocs) {
// maxHeapAllocs = curHeapAllocs;
// }
--curHeapAllocs;
}

Expand Down Expand Up @@ -120,6 +126,91 @@ class AccessRecorder {
return instance;
}

Counter getHeapAllocs() const {
return heapAllocs;
}
Counter getStackAllocs() const {
return stackAllocs;
}
Counter getGlobalAllocs() const {
return globalAllocs;
}
Counter getMaxHeapAllocs() const {
return maxHeapAllocs;
}
Counter getMaxStackAllocs() const {
return maxStackAllocs;
}
Counter getCurHeapAllocs() const {
return curHeapAllocs;
}
Counter getCurStackAllocs() const {
return curStackAllocs;
}
Counter getAddrReuses() const {
return addrReuses;
}
Counter getAddrMissing() const {
return addrMissing;
}
Counter getAddrChecked() const {
return addrChecked;
}
Counter getStackArray() const {
return stackArray;
}
Counter getHeapArray() const {
return heapArray;
}
Counter getGlobalArray() const {
return globalArray;
}
Counter getStackAllocsFree() const {
return stackAllocsFree;
}
Counter getStackArrayFree() const {
return stackArrayFree;
}
Counter getHeapAllocsFree() const {
return heapAllocsFree;
}
Counter getHeapArrayFree() const {
return heapArrayFree;
}
Counter getNullAlloc() const {
return nullAlloc;
}
Counter getZeroAlloc() const {
return zeroAlloc;
}
Counter getNullAndZeroAlloc() const {
return nullAndZeroAlloc;
}
Counter getNumUDefTypes() const {
return numUDefTypes;
}
const std::unordered_set<MemAddr>& getMissing() const {
return missing;
}
const std::unordered_set<MemAddr>& getSeen() const {
return seen;
}
const TypeCountMap& getStackAlloc() const {
return stackAlloc;
}
const TypeCountMap& getHeapAlloc() const {
return heapAlloc;
}
const TypeCountMap& getGlobalAlloc() const {
return globalAlloc;
}
const TypeCountMap& getStackFree() const {
return stackFree;
}
const TypeCountMap& getHeapFree() const {
return heapFree;
}

private:
AccessRecorder() = default;
AccessRecorder(AccessRecorder& other) = default;
Expand Down Expand Up @@ -153,9 +244,6 @@ class AccessRecorder {
TypeCountMap globalAlloc;
TypeCountMap stackFree;
TypeCountMap heapFree;

template <typename Recorder>
friend void serialise(const Recorder& r, llvm::raw_ostream& buf);
};

/**
Expand Down Expand Up @@ -198,97 +286,6 @@ class NoneRecorder {
}
};

namespace memory {
struct MemOverhead {
static constexpr auto pointerMapSize = sizeof(RuntimeT::PointerMap); // Map overhead
static constexpr auto perNodeSizeMap =
sizeof(std::remove_pointer<std::map<MemAddr, PointerInfo>::iterator::_Link_type>::type) +
sizeof(RuntimeT::MapEntry); // not applicable to btree
static constexpr auto stackVectorSize = sizeof(RuntimeT::Stack); // Stack overhead
static constexpr auto perNodeSizeStack = sizeof(RuntimeT::StackEntry); // Stack allocs
double stack{0};
double map{0};
};
inline MemOverhead estimate(Counter stack_max, Counter heap_max, Counter global_max, const double scale = 1024.0) {
MemOverhead mem;
mem.stack = double(MemOverhead::stackVectorSize +
MemOverhead::perNodeSizeStack * std::max<size_t>(RuntimeT::StackReserve, stack_max)) /
scale;
mem.map =
double(MemOverhead::pointerMapSize + MemOverhead::perNodeSizeMap * (stack_max + heap_max + global_max)) / scale;
return mem;
}
} // namespace memory

template <typename Recorder>
void serialise(const Recorder& r, llvm::raw_ostream& buf) {
if constexpr (std::is_same_v<Recorder, NoneRecorder>) {
return;
} else {
const auto memory_use = memory::estimate(r.maxStackAllocs, r.maxHeapAllocs, r.globalAllocs);

Table t("Alloc Stats from softcounters");
t.wrap_length = true;
t.put(Row::make("Total heap", r.heapAllocs, r.heapArray));
t.put(Row::make("Total stack", r.stackAllocs, r.stackArray));
t.put(Row::make("Total global", r.globalAllocs, r.globalArray));
t.put(Row::make("Max. Heap Allocs", r.maxHeapAllocs));
t.put(Row::make("Max. Stack Allocs", r.maxStackAllocs));
t.put(Row::make("Addresses checked", r.addrChecked));
t.put(Row::make("Distinct Addresses checked", r.seen.size()));
t.put(Row::make("Addresses re-used", r.addrReuses));
t.put(Row::make("Addresses missed", r.addrMissing));
t.put(Row::make("Distinct Addresses missed", r.missing.size()));
t.put(Row::make("Total free heap", r.heapAllocsFree, r.heapArrayFree));
t.put(Row::make("Total free stack", r.stackAllocsFree, r.stackArrayFree));
t.put(Row::make("Null/Zero/NullZero Addr", r.nullAlloc, r.zeroAlloc, r.nullAndZeroAlloc));
t.put(Row::make("User-def. types", r.numUDefTypes));
t.put(Row::make("Estimated memory use (KiB)", size_t(std::round(memory_use.map + memory_use.stack))));
t.put(Row::make("Bytes per node map/stack", memory::MemOverhead::perNodeSizeMap,
memory::MemOverhead::perNodeSizeStack));

t.print(buf);

std::set<int> type_id_set;
const auto fill_set = [&type_id_set](const auto& map) {
for (const auto& [key, val] : map) {
type_id_set.insert(key);
}
};
fill_set(r.heapAlloc);
fill_set(r.globalAlloc);
fill_set(r.stackAlloc);
fill_set(r.heapFree);
fill_set(r.stackFree);

const auto count = [](const auto& map, auto id) {
auto it = map.find(id);
if (it != map.end()) {
return it->second;
}
return 0ll;
};

Table type_table("Allocation type detail (heap, stack, global)");
type_table.table_header = '#';
for (auto type_id : type_id_set) {
type_table.put(Row::make(std::to_string(type_id), count(r.heapAlloc, type_id), count(r.stackAlloc, type_id),
count(r.globalAlloc, type_id), typeart_get_type_name(type_id)));
}

type_table.print(buf);

Table type_table_free("Free allocation type detail (heap, stack)");
type_table_free.table_header = '#';
for (auto type_id : type_id_set) {
type_table_free.put(Row::make(std::to_string(type_id), count(r.heapFree, type_id), count(r.stackFree, type_id),
typeart_get_type_name(type_id)));
}

type_table_free.print(buf);
}
}

} // namespace softcounter

#if ENABLE_SOFTCOUNTER == 1
Expand Down
1 change: 1 addition & 0 deletions lib/runtime/Runtime.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "Runtime.h"

#include "AccessCountPrinter.h"
#include "AccessCounter.h"
#include "RuntimeInterface.h"
#include "support/Logger.h"
Expand Down
Loading