From 6ddafafa7292f6f6716d6683579bf1ce3287e1d5 Mon Sep 17 00:00:00 2001 From: Julian Blake Kongslie Date: Sat, 15 Oct 2022 14:01:38 -0700 Subject: Initial commit (copied from biggolf) --- arbiter.h | 55 +++++++++++++++++++++++++++++++ pipetrace.cpp | 9 +++++ pipetrace.h | 37 +++++++++++++++++++++ port.h | 45 +++++++++++++++++++++++++ pt | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ queue.h | 29 ++++++++++++++++ sim.cpp | 9 +++++ sim.h | 38 +++++++++++++++++++++ stat.h | 35 ++++++++++++++++++++ 9 files changed, 361 insertions(+) create mode 100644 arbiter.h create mode 100644 pipetrace.cpp create mode 100644 pipetrace.h create mode 100644 port.h create mode 100755 pt create mode 100644 queue.h create mode 100644 sim.cpp create mode 100644 sim.h create mode 100644 stat.h diff --git a/arbiter.h b/arbiter.h new file mode 100644 index 0000000..79a9920 --- /dev/null +++ b/arbiter.h @@ -0,0 +1,55 @@ +#pragma once + +#include +#include + +#include "infra/sim.h" + +namespace infra { + template struct priority_arbiter : public sim { + std::array, peers> peerp; + port *outp = nullptr; + + void clock() { + for (unsigned int i = 0; i < peers; ++i) { + if (outp->can_write() && peerp[i].can_read()) + outp->write(peerp[i].read()); + } + } + }; + + template struct round_robin_arbiter : public sim { + std::array, peers> peerp; + port *outp = nullptr; + unsigned int initial = 0; + + void clock() { + bool initially_empty = outp->can_write(); + for (unsigned int i = initial; i < peers; ++i) { + if (outp->can_write() && peerp[i].can_read()) + outp->write(peerp[i].read()); + } + for (unsigned int i = 0; i < initial; ++i) { + if (outp->can_write() && peerp[i].can_read()) + outp->write(peerp[i].read()); + } + if (initially_empty && !outp->can_write()) + if (++initial == peers) + initial = 0; + } + }; + + template struct shared_bus : public sim { + std::array, peers> peerp; + port *outp = nullptr; + + void clock() { + for (unsigned int i = 0; i < peers; ++i) { + if (peerp[i].can_read()) { + assert(outp->can_write()); + outp->write(peerp[i].read()); + } + } + } + }; +} diff --git a/pipetrace.cpp b/pipetrace.cpp new file mode 100644 index 0000000..e6642ef --- /dev/null +++ b/pipetrace.cpp @@ -0,0 +1,9 @@ +#include +#include + +#include "infra/pipetrace.h" + +namespace infra { + std::ostream *pt::ptfile = nullptr; + std::uint64_t pt::next_record = 0; +} diff --git a/pipetrace.h b/pipetrace.h new file mode 100644 index 0000000..656b9b9 --- /dev/null +++ b/pipetrace.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include +#include + +namespace infra { + struct transaction { + std::uint64_t record = ~(std::uint64_t)0; + }; + + struct pt { + static std::ostream *ptfile; + + static std::uint64_t next_record; + + static transaction toplevel() { + transaction t; + t.record = next_record++; + return t; + } + + static transaction child(const transaction &p) { + transaction t; + t.record = next_record++; + if (ptfile) + *ptfile << fmt::format("{} parent {}\n", t.record, p.record); + return t; + } + + static void event(const transaction &t, const char *event, std::uint64_t time, const std::string &data) { + if (ptfile) + *ptfile << fmt::format("@{} {} {} {}\n", time, t.record, event, data); + } + }; +} diff --git a/port.h b/port.h new file mode 100644 index 0000000..06a3aa5 --- /dev/null +++ b/port.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include +#include + +#include "infra/sim.h" + +namespace infra { + template struct port : public sim { + std::optional consumer_side; + std::optional producer_side; + + bool can_read() { return consumer_side.has_value(); } + bool can_write() { return !producer_side.has_value(); } + + T read() { + assert(can_read()); + auto x = std::move(*consumer_side); + consumer_side.reset(); + return x; + } + + const T & peek() { + assert(can_read()); + return *consumer_side; + } + + void discard() { + consumer_side.reset(); + } + + void write(T &&x) { + assert(can_write()); + producer_side = std::move(x); + } + + void unclock() { + if (!consumer_side && producer_side) { + consumer_side = std::move(*producer_side); + producer_side.reset(); + } + } + }; +} diff --git a/pt b/pt new file mode 100755 index 0000000..206795f --- /dev/null +++ b/pt @@ -0,0 +1,104 @@ +#!/usr/bin/ruby + +$filter = ARGV + +$parents = {} +$events = {} +$has = {} +$data = {} +$horiz = {} +$maxtime = -1 + +$stats = false + +$stdin.each_line do | line | + case line + + when /^(\d+) parent (\d+)$/ + child = $1.to_i + parent = $2.to_i + $parents[child] = parent + + when /^@(\d+) (\d+) (\S*) (.*)$/ + time = $1.to_i + rec = $2.to_i + event = $3 + data = $4 + if event.size > 0 + $events[rec] ||= {} + $events[rec][time] = event + $has[rec] ||= {} + $has[rec][event] = true + $horiz[event] ||= "" + $horiz[event] = $horiz[event].ljust(time) + $horiz[event][time] = event + end + if data.size > 0 + $data[rec] ||= "" + $data[rec] += " #{event}@#{time}:" if event.size > 0 + $data[rec] += " #{data}" + end + $maxtime = [$maxtime, time+1].max + + when /^#\s*(.*)$/ + $stats = true + $stdout.write("#{$1}\n") + + else + raise "Unexpected line: #{line}" + end +end + +$stdout.write("\n") if $stats + +$hier = {} +$hier_direct = {} + +$events.each_key do | rec | + subhier = {} + $hier_direct[rec] = subhier + if $parents.key?(rec) + $hier_direct[$parents[rec]][rec] = subhier + else + $hier[rec] = subhier + end +end + +$order = [] + +def flatten(hier) + hier.each do | rec, subhier | + $order << rec + flatten(subhier) + end +end +flatten($hier) + +rwidth = $order.map { | x | x.to_s.size }.max + +$horiz.keys.sort.each do | occ | + $stdout.write(" " * rwidth + " #{$horiz[occ].ljust($maxtime)}") + count = $horiz[occ].delete(" ").size + $stdout.write(" #{($maxtime.to_f / count.to_f).round(2).to_s.rjust(5)} cyc/evt\n") +end +$stdout.write("\n") + +mwidth = 0 + +$order.each do | rec | + estr = "" + filter_match = $filter.empty? + $has[rec].each_key do | event | + filter_match ||= $filter.include?(event) + end + next unless filter_match + $events[rec].keys.sort.each do | time | + estr = estr.ljust(time + 1, estr.size == 0 ? " " : "-") + estr[time] = $events[rec][time] if $events[rec][time].size > 0 + end + estr += " " * 5 + estr = estr.ljust(mwidth - 1) + estr = estr.ljust(estr.size + 20 - estr.size % 20) + mwidth = [mwidth, estr.size].max + $stdout.write(rec.to_s.rjust(rwidth) + ": #{estr}#{$data[rec]}\n") +end diff --git a/queue.h b/queue.h new file mode 100644 index 0000000..1e490bc --- /dev/null +++ b/queue.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include +#include + +#include "infra/port.h" +#include "infra/sim.h" + +namespace infra { + template struct queue : public sim { + port input; + port *output = nullptr; + std::deque elements; + + void clock() { + if (input.can_read() && elements.size() < size) { + auto x = input.read(); + elements.emplace_back(std::move(x)); + } + if (output->can_write() && !elements.empty()) { + auto &x = elements.front(); + output->write(std::move(x)); + elements.pop_front(); + } + } + }; +} diff --git a/sim.cpp b/sim.cpp new file mode 100644 index 0000000..21acc8c --- /dev/null +++ b/sim.cpp @@ -0,0 +1,9 @@ +#include +#include + +#include "infra/sim.h" + +namespace infra { + std::vector sim::sims; + std::uint64_t sim::now = 0; +} diff --git a/sim.h b/sim.h new file mode 100644 index 0000000..185916a --- /dev/null +++ b/sim.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include + +#include "infra/pipetrace.h" + +namespace infra { + struct sim { + virtual void clock() {} + virtual void unclock() {} + + static std::vector sims; + + static std::uint64_t now; + + sim() { + sims.emplace_back(this); + } + + virtual ~sim() { + std::erase(sims, this); + } + + static void advance() { + for (auto &s : sims) + s->clock(); + for (auto &s : sims) + s->unclock(); + ++now; + } + + void pte(const transaction &t, const char *event, const std::string &data) { + pt::event(t, event, now, data); + } + }; +} diff --git a/stat.h b/stat.h new file mode 100644 index 0000000..f1ca75a --- /dev/null +++ b/stat.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +#include "infra/sim.h" + +namespace infra { + struct stat : public sim { + std::string name; + std::uint64_t numerator = 0; + std::uint64_t denominator = 0; + + stat(std::string name) + : name(std::move(name)) + { } + + ~stat() { + fmt::print("# {} {}\n", name, (double)numerator/(double)denominator); + } + + void unclock() { + ++denominator; + } + + stat & operator++() { + ++numerator; + return *this; + } + + stat & operator++(int) { + return operator++(); + } + }; +} -- cgit v1.2.3