Compare commits

...

14 Commits

6
.gitignore vendored

@ -1,6 +1,8 @@
*~ *~
test* test*
obj/ obj/
hexview hexview-*
hexview-pgo
profile/ profile/
perf.*
flamegraph.svg

@ -1,14 +1,18 @@
SRC=$(wildcard src/*.cpp) SRC=$(wildcard src/*.cpp)
INCLUDE =include INCLUDE =include
_HX_FEAT?= -DFIXED_ROW_SIZE=24 _HX_FEAT?= -DFIXED_ROW_SIZE=24
CXXFLAGS?= -pipe -O3 -march=native CXXFLAGS_COMMON = -Wall -pedantic --std=gnu++20 $(addprefix -I,$(INCLUDE)) -felide-constructors -fno-strict-aliasing -fno-exceptions
CXXFLAGS+= -flto -felide-constructors -fgraphite -fno-strict-aliasing -fno-exceptions -fomit-frame-pointer -fmerge-all-constants -fmodulo-sched -funswitch-loops -fsplit-loops LDFLAGS_COMMON = -lfmt
CXXFLAGS+= -Wall -pedantic --std=gnu++20 $(addprefix -I,$(INCLUDE))
LDFLAGS?= -O3 -flto CXXFLAGS_DEFAULT = -pipe -O3 -march=native -fgraphite -flto
LDFLAGS+= -lfmt CXXFLAGS_RELEASE = -fomit-frame-pointer -fmerge-all-constants -fmodulo-sched -funswitch-loops -fsplit-loops
LDFLAGS_DEFAULT = -O3 -flto
CXXFLAGS_DEBUG = -DDEBUG -O0 -g
PROJ = hexview PROJECT = hexview
OBJ = $(addprefix obj/,$(SRC:.cpp=.o)) OBJ = $(addprefix obj/,$(SRC:.cpp=.o))
@ -24,8 +28,14 @@ PROF_FLAGS = -fprofile-generate
### ###
.PHONY: all .PHONY: release
all: | dirs $(PROJ) release: | dirs $(PROJECT)-release
.PHONY: debug
debug: | dirs $(PROJECT)-debug
.PHONY: pgo
pgo: | dirs $(PROJECT)-pgo
dirs: dirs:
@mkdir -p obj/src @mkdir -p obj/src
@ -37,38 +47,62 @@ obj/%.o: %.cpp
profile/%.o: %.cpp profile/%.o: %.cpp
$(CXX) -c $< $(_HX_FEAT) $(CXXFLAGS) $(PROF_FLAGS) -o $@ $(LDFLAGS) $(PROF_FLAGS) $(CXX) -c $< $(_HX_FEAT) $(CXXFLAGS) $(PROF_FLAGS) -o $@ $(LDFLAGS) $(PROF_FLAGS)
$(PROJ): $(OBJ) $(PROJECT)-release: CXXFLAGS?= $(CXXFLAGS_DEFAULT)
$(PROJECT)-release: LDFLAGS?= $(LDFLAGS_DEFAULT)
$(PROJECT)-release: CXXFLAGS+= $(CXXFLAGS_COMMON)
$(PROJECT)-release: CXXFLAGS+= $(CXXFLAGS_RELEASE)
$(PROJECT)-release: LDFLAGS := $(LDFLAGS_COMMON) $(LDFLAGS)
$(PROJECT)-release: $(OBJ)
$(CXX) $^ $(CXXFLAGS) -o $@ $(LDFLAGS) $(CXX) $^ $(CXXFLAGS) -o $@ $(LDFLAGS)
strip $@ strip $@
$(PROJECT)-debug: CXXFLAGS += $(CXXFLAGS_COMMON)
$(PROJECT)-debug: CXXFLAGS += $(CXXFLAGS_DEBUG)
$(PROJECT)-debug: LDFLAGS += $(LDFLAGS_COMMON)
$(PROJECT)-debug: $(OBJ)
$(CXX) $^ $(CXXFLAGS) -o $@ $(LDFLAGS)
pgo-generate: $(PGO_OBJ) pgo-generate: $(PGO_OBJ)
$(CXX) $^ $(CXXFLAGS) $(PROF_FLAGS) -o $@ $(LDFLAGS) $(PROF_FLAGS) $(CXX) $^ $(CXXFLAGS) $(PROF_FLAGS) -o $@ $(LDFLAGS) $(PROF_FLAGS)
pgo-profile: pgo-generate pgo-reset:
find ./profile -name \*.gcda -exec rm {} +
pgo-profile: | pgo-reset pgo-generate
for i in {1..$(PGO_ITERATIONS)}; do \ for i in {1..$(PGO_ITERATIONS)}; do \
dd if=/dev/urandom of=./pgo-test bs=1024 count=$(PGO_DATASET_SIZE) >> /dev/null 2>&1; \ dd if=/dev/urandom of=/tmp/$(PROJECT)-pgo-test bs=1024 count=$(PGO_DATASET_SIZE) >> /dev/null 2>&1; \
printf "\rIteration $$i / $(PGO_ITERATIONS)"; \ printf "\rIteration $$i / $(PGO_ITERATIONS)"; \
./pgo-generate ./pgo-test > ./pgo-output; \ ./pgo-generate /tmp/$(PROJECT)-pgo-test > /tmp/$(PROJECT)-pgo-output; \
done done
@echo "" @echo ""
rm ./pgo-test rm /tmp/$(PROJECT)-pgo-test
rm ./pgo-output rm /tmp/$(PROJECT)-pgo-output
rm pgo-generate rm pgo-generate
pgo-use: PROF_FLAGS = -fprofile-use -lgcov pgo-use: CXXFLAGS?= $(CXXFLAGS_DEFAULT)
pgo-use: LDFLAGS?= $(LDFLAGS_DEFAULT)
pgo-use: CXXFLAGS+= $(CXXFLAGS_COMMON)
pgo-use: CXXFLAGS+= $(CXXFLAGS_RELEASE)
pgo-use: LDFLAGS := $(LDFLAGS_COMMON) -lgcov $(LDFLAGS)
pgo-use: PROF_FLAGS = -fprofile-use
pgo-use: $(PGO_OBJ) pgo-use: $(PGO_OBJ)
$(CXX) $^ $(CXXFLAGS) $(PROF_FLAGS) -o $@ $(LDFLAGS) $(PROF_FLAGS) $(CXX) $^ $(CXXFLAGS) $(PROF_FLAGS) -o $@ $(LDFLAGS) $(PROF_FLAGS)
$(PROJ)-pgo: | dirs pgo-profile $(PROJECT)-pgo: CXXFLAGS?= $(CXXFLAGS_DEFAULT)
$(PROJECT)-pgo: LDFLAGS?= $(LDFLAGS_DEFAULT)
$(PROJECT)-pgo: CXXFLAGS+= $(CXXFLAGS_COMMON)
$(PROJECT)-pgo: CXXFLAGS+= $(CXXFLAGS_RELEASE)
$(PROJECT)-pgo: LDFLAGS := $(LDFLAGS_COMMON) $(LDFLAGS)
$(PROJECT)-pgo: | dirs pgo-profile
find ./profile -name \*.o -exec rm {} + find ./profile -name \*.o -exec rm {} +
$(MAKE) pgo-use $(MAKE) pgo-use
mv pgo-use $@ mv pgo-use $@
strip $@ strip $@
clean: clean:
rm -f $(PROJ) rm -f $(PROJECT)-{release,debug,pgo}
rm -f $(PROJ)-pgo
rm -rf obj rm -rf obj
rm -rf profile rm -rf profile
rm -f pgo-{test,output,generate} rm -f pgo-{test,output,generate}

@ -5,4 +5,42 @@
namespace hv { namespace hv {
/// Print a single screen /// Print a single screen
void print_screen(const span<unsigned char> bytes, unsigned long offset); void print_screen(const span<unsigned char> bytes, unsigned long offset);
inline void lookup_hex_string(std::uint64_t x, char* s)
{
static const char digits[513] =
"000102030405060708090a0b0c0d0e0f"
"101112131415161718191a1b1c1d1e1f"
"202122232425262728292a2b2c2d2e2f"
"303132333435363738393a3b3c3d3e3f"
"404142434445464748494a4b4c4d4e4f"
"505152535455565758595a5b5c5d5e5f"
"606162636465666768696a6b6c6d6e6f"
"707172737475767778797a7b7c7d7e7f"
"808182838485868788898a8b8c8d8e8f"
"909192939495969798999a9b9c9d9e9f"
"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"
"b0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
"c0c1c2c3c4c5c6c7c8c9cacbcccdcecf"
"d0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
"e0e1e2e3e4e5e6e7e8e9eaebecedeeef"
"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
int i = 7;
const char *lut = (const char *)digits;
while (i >= 0)
{
int pos = (x & 0xFF) * 2;
char ch = lut[pos];
#ifdef DEBUG
if ( (i*2+1) >=16) std::terminate();
#endif
s[i * 2] = ch;
ch = lut[pos + 1];
s[i * 2 + 1] = ch;
x >>= 8;
i -= 1;
}
}
} }

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <exception>
#include <cstdint> #include <cstdint>
#include <cmath> #include <cmath>
@ -20,14 +21,14 @@ namespace hv
inline T& operator[](std::size_t index) inline T& operator[](std::size_t index)
{ {
#ifdef DEBUG #ifdef DEBUG
if (index>=len) throw "tried to index out of bounds of array"; if (index>=len) std::terminate(); // "tried to index out of bounds of array";
#endif #endif
return ptr[index]; return ptr[index];
} }
inline const T& operator[](std::size_t index) const inline const T& operator[](std::size_t index) const
{ {
#ifdef DEBUG #ifdef DEBUG
if (index>=len) throw "tried to index out of bounds of array"; if (index>=len) std::terminate(); // "tried to index out of bounds of array";
#endif #endif
return ptr[index]; return ptr[index];
} }
@ -35,12 +36,12 @@ namespace hv
inline span<T> slice(std::size_t off, std::size_t len) inline span<T> slice(std::size_t off, std::size_t len)
{ {
len = std::min(this->len, len); len = std::min(this->len, len);
if(len+off>=len || len < off) throw "tried to index out of bounds of array"; if(len+off>=len || len < off) std::terminate(); // "tried to index out of bounds of array";
return span<T>(ptr+off, len-off); return span<T>(ptr+off, len-off);
} }
inline span<T> slice(std::size_t off) inline span<T> slice(std::size_t off)
{ {
if(len+off>=len || len < off) throw "tried to index out of bounds of array"; if(len+off>=len || len < off) std::terminate(); // "tried to index out of bounds of array";
return span<T>(ptr+off, len-off); return span<T>(ptr+off, len-off);
} }

@ -1,5 +1,6 @@
#include <fmt/format.h> #include <fmt/format.h>
#include <span.hpp> #include <span.hpp>
#include <hex.hpp>
const static constexpr char ascii_map[256] = { const static constexpr char ascii_map[256] = {
'.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.',
@ -20,7 +21,7 @@ const static constexpr char ascii_map[256] = {
'.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.',
}; };
constexpr const char* hex_map[256] = { constexpr const static char* hex_map[256] = {
"00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", "0b", "0c", "0d", "0e", "0f", "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", "0b", "0c", "0d", "0e", "0f",
"10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1a", "1b", "1c", "1d", "1e", "1f", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1a", "1b", "1c", "1d", "1e", "1f",
"20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2a", "2b", "2c", "2d", "2e", "2f", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2a", "2b", "2c", "2d", "2e", "2f",
@ -59,52 +60,80 @@ inline void hex02(std::uint8_t byte, char buffer[2])
buffer[1] =hex_map[byte][1]; buffer[1] =hex_map[byte][1];
} }
template<int N> template<std::size_t N>
inline __attribute__((always_inline)) void print_exact(const char* ar)
{
fwrite(ar, 1, N, stdout);
}
template<std::size_t N>
inline __attribute__((always_inline)) void print_exact(const char (&ar)[N]) inline __attribute__((always_inline)) void print_exact(const char (&ar)[N])
{ {
fwrite(ar, N, 1, stdout); fwrite(ar, N, 1, stdout);
} }
inline static void u64_to_hex(std::uint64_t num, char* s)
{
hv::lookup_hex_string(num, s);
}
namespace hv { namespace hv {
void print_screen(const span<unsigned char> memory, unsigned long offset) void print_screen(const span<unsigned char> memory, unsigned long offset)
{ {
#ifndef FIXED_ROW_SIZE #ifndef FIXED_ROW_SIZE
#define S (const char*) #define S (2+ROW_SZ)
#define P_EX(n, buf) fwrite(buf, 1, n, stdout)
int ROW_SZ = 24; int ROW_SZ = 24;
#else #else
#define S #define S
#define P_EX(n, buf) print_exact(buf)
#endif #endif
fmt::print("0x{:016x} ", offset); char posbuf[3 + 16 + 2];
char hxbuf[3]; posbuf[0] = '\n';
posbuf[1] = '0';
posbuf[2] = 'x';
#ifdef DEBUG
std::memset(posbuf+3, '0', 16);
#endif
posbuf[3 + 16] = ' ';
posbuf[3 + 16 + 1] = ' ';
u64_to_hex(offset, posbuf+3);
prints(posbuf+1);
char hxbuf[3] = { ' ', ' ', ' ' };
std::size_t i=0; std::size_t i=0;
char r_ascii[2 + ROW_SZ]; char r_ascii[2 + ROW_SZ];
r_ascii[0] = ' '; r_ascii[0] = ' ';
r_ascii[1] = ' '; r_ascii[1] = ' ';
char* ascii = r_ascii + 2; char* ascii = r_ascii + 2;
const auto memsize = memory.size();
hxbuf[2] = ' '; for(;i<memsize;i++) {
for(;i<memory.size();i++) {
if (i && i % ROW_SZ == 0) { //TODO: Change to i +=16 so we don't have to branch here on every byte. Make sure to not overrun buffer tho if (i && i % ROW_SZ == 0) { //TODO: Change to i +=16 so we don't have to branch here on every byte. Make sure to not overrun buffer tho
print_exact(r_ascii); P_EX(S, r_ascii);
fmt::print("\n0x{:016x} ", i+offset);
u64_to_hex(i+offset, posbuf+3);
print_exact(posbuf);
} }
unsigned char idx = memory[i]; unsigned char idx = memory[i];
hex02(idx, hxbuf); hex02(idx, hxbuf);
print_exact(hxbuf); print_exact(hxbuf);
ascii[i%ROW_SZ] = ascii_map[idx]; ascii[i%ROW_SZ] = ascii_map[idx];
} }
if (memory.size() % ROW_SZ != 0) if (memsize % ROW_SZ != 0)
{ {
auto rest = memory.size() % ROW_SZ; auto rest = memsize % ROW_SZ;
ascii[rest] = 0; ascii[rest] = 0;
constexpr const char output[3] = { ' ', ' ', ' ' }; constexpr const char output[3] = { ' ', ' ', ' ' };
for(std::size_t j=0;j< ROW_SZ - rest;j++) for(std::size_t j=0;j< ROW_SZ - rest;j++)
print_exact(output); print_exact(output);
prints(r_ascii); prints((const char*) r_ascii);
} }
else { else {
print_exact(r_ascii); P_EX(S, r_ascii);
} }
} }
} }

Loading…
Cancel
Save