Skip to content

Commit

Permalink
Fix tape realtime play
Browse files Browse the repository at this point in the history
  • Loading branch information
prybicki committed Mar 14, 2024
1 parent 203dcc7 commit 878898b
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 15 deletions.
2 changes: 1 addition & 1 deletion src/api/apiCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1258,7 +1258,7 @@ RGL_API rgl_status_t rgl_tape_play(const char* path)
throw RecordError("rgl_tape_play: recording active");
} else {
TapePlayer player(path);
player.playRealtime();
player.playApproximatelyRealtime();
}
});
#endif //_WIN32
Expand Down
37 changes: 26 additions & 11 deletions src/tape/TapePlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <filesystem>
#include <fstream>
#include <cassert>
#include <thread>

#include <tape/TapePlayer.hpp>
#include <tape/tapeDefinitions.hpp>
Expand All @@ -23,14 +24,11 @@

namespace fs = std::filesystem;

TapePlayer::TapePlayer(const char* path)
TapePlayer::TapePlayer(const char* path) : path(path)
{
std::string pathYaml = fs::path(path).concat(YAML_EXTENSION).string();
std::string pathBin = fs::path(path).concat(BIN_EXTENSION).string();

playbackState = std::make_unique<PlaybackState>(pathBin.c_str());
playbackState = std::make_unique<PlaybackState>(getBinPath().c_str());

yamlRoot = YAML::LoadFile(pathYaml);
yamlRoot = YAML::LoadFile(getYamlPath());
if (yamlRoot.IsNull()) {
throw RecordError("Invalid Tape: Empty YAML file detected");
}
Expand All @@ -43,6 +41,10 @@ TapePlayer::TapePlayer(const char* path)
nextCallIdx = 0;
}

std::string TapePlayer::getBinPath() const { return fs::path(path).concat(BIN_EXTENSION).string(); }

std::string TapePlayer::getYamlPath() const { return fs::path(path).concat(YAML_EXTENSION).string(); }

void TapePlayer::checkTapeVersion()
{
auto versionCallIdx = findFirst({RGL_VERSION});
Expand Down Expand Up @@ -110,8 +112,6 @@ void TapePlayer::playUntil(std::optional<APICallIdx> breakpoint)
}
}

void TapePlayer::rewindTo(APICallIdx nextCall) { this->nextCallIdx = nextCall; }

void TapePlayer::playThis(APICallIdx idx)
{
const TapeCall& call = getTapeCall(idx);
Expand All @@ -121,15 +121,30 @@ void TapePlayer::playThis(APICallIdx idx)
tapeFunctions[call.getFnName()](call.getArgsNode(), *playbackState);
}

#include <thread>
void TapePlayer::playRealtime()

void TapePlayer::playApproximatelyRealtime()
{
// Approximation comes from the fact that we don't account for the time it takes to execute the function
// This could be fixed by moving TAPE_HOOK to the beginning of the API call
// It might be a good idea to do so, because it would record failed calls.
auto beginTimestamp = std::chrono::steady_clock::now();
TapeCall nextCall = getTapeCall(nextCallIdx);
for (; nextCallIdx < yamlRoot.size(); ++nextCallIdx) {
TapeCall nextCall = getTapeCall(nextCallIdx);
auto nextCallNs = std::chrono::nanoseconds(nextCall.getTimestamp().asNanoseconds());
auto elapsed = std::chrono::steady_clock::now() - beginTimestamp;
std::this_thread::sleep_for(nextCallNs - elapsed);
playThis(nextCallIdx);
}
}

void TapePlayer::reset()
{
auto status = rgl_cleanup();
if (status != RGL_SUCCESS) {
const char* error = nullptr;
rgl_get_last_error_string(&error);
throw RecordError(fmt::format("Failed to reset playback state: {}", error));
}
nextCallIdx = 0;
playbackState = std::make_unique<PlaybackState>(getBinPath().c_str());
}
7 changes: 5 additions & 2 deletions src/tape/TapePlayer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,18 @@ struct TapePlayer
void playThis(APICallIdx idx);
void playThrough(APICallIdx last);
void playUntil(std::optional<APICallIdx> breakpoint = std::nullopt);
void playRealtime();
void rewindTo(APICallIdx nextCall = 0);
void playApproximatelyRealtime();
void reset();

rgl_node_t getNodeHandle(TapeAPIObjectID key) { return playbackState->nodes.at(key); }

private:
YAML::Node yamlRoot{};
APICallIdx nextCallIdx{};
std::unique_ptr<PlaybackState> playbackState;
std::string path;

static inline std::map<std::string, TapeFunction> tapeFunctions = {};
std::string getBinPath() const;
std::string getYamlPath() const;
};
5 changes: 4 additions & 1 deletion tools/tapePlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ int main(int argc, char** argv)
return 1;
}
TapePlayer player{argv[1]};
player.playUntil();
while (true) {
player.playApproximatelyRealtime();
player.reset();
}
return 0;
}

0 comments on commit 878898b

Please sign in to comment.