Skip to content
Snippets Groups Projects
Commit 7ccf7d14 authored by Hashim Sharif's avatar Hashim Sharif
Browse files

Merging

parents b2ac7220 57f114b5
No related branches found
No related tags found
No related merge requests found
Showing
with 254 additions and 0 deletions
*.swp
jetsonTX2Power
pp
all:
g++ -std=c++11 -O3 profiler.cpp -o pp -lpthread
clean:
rm -rf pp
#!/bin/sh
input=$1
gnuplot -p << EOF
#set terminal png
#set output "$input.png"
set xlabel "Time (s)"
set ylabel "Power (mW)"
set title "Power usage of GPU and DDR over time"
plot "$input" using 1:2 title 'GPU' with lines,"$input" using 1:3 title 'DDR' with lines
EOF
#include <atomic>
#include <chrono>
#include <cmath>
#include <condition_variable>
#include <fstream>
#include <iostream>
#include <string>
#include <thread>
#include <vector>
// Reads power rails at runtime and computes the GPU and DDR energy within a window
// of time, which is delimitered by the calls to resume_profiler() and stop_profiler()
//
// IMPORTANT: Must call exit_profiler() to kill the profiler thread
//
// Public interface methods:
// void initialize();
// void run_profiler();
// void resume_profiler();
// void stop_profiler();
// std::pair<double, double> get_time_energy() const;
// void reset()
// void exit_profiler();
class Profiler {
public:
Profiler() : should_run_profiler_(false), should_exit_profiler_(false) {
// Open all streams. Not done in initialize() function bc the streams
// should be strictly opened once
cpu_stream_.open(cpu_power_rail, std::ifstream::in);
gpu_stream_.open(gpu_power_rail, std::ifstream::in);
ddr_stream_.open(ddr_power_rail, std::ifstream::in);
soc_stream_.open(soc_power_rail, std::ifstream::in);
sys_stream_.open(sys_power_rail, std::ifstream::in);
if (!cpu_stream_.is_open() or !gpu_stream_.is_open() or !ddr_stream_.is_open()
or !soc_stream_.is_open() or !sys_stream_.is_open()) {
std::cout << "Failed to open one of the power rails for reading\n";
exit(1);
}
}
~Profiler() {
cpu_stream_.close();
gpu_stream_.close();
ddr_stream_.close();
soc_stream_.close();
sys_stream_.close();
}
// Reinitializes boolean vars used for control flow and launches the profiler
// thread. DOES NOT reset other internal data structures.
void initialize(){
// Reinitialize in case the profiler object has been used before
should_run_profiler_ = false;
should_exit_profiler_ = false;
// Launch profiler thread
profiler_thread_ = std::thread(&Profiler::run_profiler, this);
}
// Runs the profiler thread, keeping it alive by wrapping the functionality
// in an infinite loop
void run_profiler(){
while (true){
if (should_exit_profiler_) {
break;
}
// TODO overhead between calls to obtain_power_reading
// Need to lock the mutex and check the condition var
{
std::unique_lock<std::mutex> mutex_lock(mutex_);
if (should_exit_profiler_) {
break;
}
// Wake the thread up when it's time to run the profiler or exit
// the profiler
cond_var_.wait(mutex_lock, [this]{return should_run_profiler_
|| should_exit_profiler_; });
}
if (should_exit_profiler_) {
break;
}
obtain_power_reading();
}
}
// Resumes the profiling of whatever executable's currently running
// DOES NOT reset any data
void resume_profiler() {
{
std::unique_lock<std::mutex> mutex_lock(mutex_);
if (should_run_profiler_){
std::cout << "WARNING: resume_profiler was already called\n";
}
should_run_profiler_ = true;
start_time_ = std::chrono::high_resolution_clock::now();
}
cond_var_.notify_one();
}
// Stops profiler by putting profiler thread to sleep
void stop_profiler() {
{
std::unique_lock<std::mutex> mutex_lock(mutex_);
if (!should_run_profiler_){
std::cout << "WARNING: stop_profiler was already called\n";
}
should_run_profiler_ = false;
}
cond_var_.notify_one();
}
// Gets the delta time and total GPU and DDR energy between the last two
// calls to resume_profiler and stop_profiler
//
// Returns this as a pair of <delta time in milliseconds, energy>
std::pair<double, double> get_time_energy() const {
double total_energy = 0.0;
std::chrono::time_point<std::chrono::high_resolution_clock> prev_time = start_time_;
for (auto reading : power_readings_) {
std::chrono::duration<double> duration = reading.time_ - prev_time;
total_energy += reading.gpu_ * duration.count();
total_energy += reading.ddr_ * duration.count();
prev_time = reading.time_;
}
double delta_time = std::chrono::duration<double, std::milli>(prev_time
- start_time_).count();
return std::make_pair(delta_time, total_energy);
}
// Resets all internal data structures, including the vector storing all power_readings.
void reset() {
should_exit_profiler_ = false; // Can call reset after calling exit_profiler()
should_run_profiler_ = false; // Can call reset after calling resume
power_readings_.clear();
}
// Exit the profiler and kill the thread
// Must call initialize() to reuse this object after calling exit_profiler()
void exit_profiler() {
std::cout << "Exiting profiler\n";
should_exit_profiler_ = true;
cond_var_.notify_one();
profiler_thread_.join();
}
private:
// Power rails are mounted as files. Keeping the old power rail file names for possible future
// integrations
const std::string cpu_power_rail = "/sys/devices/3160000.i2c/i2c-0/0-0041/iio_device/in_power1_input";
const std::string gpu_power_rail = "/sys/devices/3160000.i2c/i2c-0/0-0040/iio_device/in_power0_input";
const std::string ddr_power_rail = "/sys/devices/3160000.i2c/i2c-0/0-0041/iio_device/in_power2_input";
const std::string soc_power_rail = "/sys/devices/3160000.i2c/i2c-0/0-0040/iio_device/in_power1_input";
const std::string sys_power_rail = "/sys/devices/3160000.i2c/i2c-0/0-0041/iio_device/in_power0_input";
// An individual power reading
struct PowerReading {
std::chrono::time_point<std::chrono::high_resolution_clock> time_;
double cpu_;
double gpu_;
double ddr_;
double soc_;
double sys_;
};
// Stores all power readings and is cleared only when reset() is called
std::vector<PowerReading> power_readings_;
std::chrono::time_point<std::chrono::high_resolution_clock> start_time_;
// For reading the i2c buses via sysfs
std::ifstream cpu_stream_;
std::ifstream gpu_stream_;
std::ifstream ddr_stream_;
std::ifstream soc_stream_;
std::ifstream sys_stream_;
std::mutex mutex_;
std::condition_variable cond_var_;
bool should_run_profiler_; // True if we want to resume the profiling thread
std::atomic_bool should_exit_profiler_; // Quit profiling
std::thread profiler_thread_;
// Obtain's a single power reading from the GPU and DDR rails
void obtain_power_reading() {
PowerReading reading;
// The order matters here. All the reads have to happen together first
// and then all the seeks have to happen together at the end, otherwise
// there will be a significant time difference between the readings of
// the different rails.
reading.time_ = std::chrono::high_resolution_clock::now();
gpu_stream_ >> reading.gpu_;
ddr_stream_ >> reading.ddr_;
power_readings_.push_back(reading);
// Reset the input position of the files
gpu_stream_.seekg(0);
ddr_stream_.seekg(0);
}
};
/*
// TESTS
void resume_pause_profiler(Profiler& profile_wrapper, unsigned long sleep_millis){
profile_wrapper.resume_profiler();
std::this_thread::sleep_for(std::chrono::milliseconds(sleep_millis));
profile_wrapper.stop_profiler();
auto time_energy_pair = profile_wrapper.get_time_energy();
profile_wrapper.reset();
printf("time: %f, energy: %f\n", time_energy_pair.first, time_energy_pair.second);
std::this_thread::sleep_for(std::chrono::milliseconds(sleep_millis));
}
int main(){
Profiler profile_wrapper;
profile_wrapper.initialize();
unsigned long sleep_millis = 5000;
resume_pause_profiler(profile_wrapper, sleep_millis);
resume_pause_profiler(profile_wrapper, sleep_millis);
resume_pause_profiler(profile_wrapper, sleep_millis);
resume_pause_profiler(profile_wrapper, sleep_millis);
// IMPORTANT
profile_wrapper.exit_profiler();
return 0;
}
*/
File added
File added
File added
File added
File added
File added
File added
File added
File added
File added
File added
File added
File added
File added
File added
File added
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment