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

Benchmark cache #955

Open
wants to merge 56 commits into
base: dev
Choose a base branch
from
Open

Benchmark cache #955

wants to merge 56 commits into from

Conversation

jessevz
Copy link
Contributor

@jessevz jessevz commented Jul 25, 2023

made a cache for the benchmarks so that benchmarks can be reused and the benchmark proces can be skipped when the benchmark has already been cached.
Key components:

  • Added a benchmark model. The benchmark model got a field for all the dependencies of the benchmark output. These are the benchmark type (speed or runtime), the cracker binary, the hardware that is used, the attack parameters and the hashmode.
  • Agents are split up into hardware groups, so that benchmark can be linked to a hardwaregroup and not a single agent.
  • Benchmarks get invalidated by a time to live.
  • frontend for the benchmarks in /benchmark.php to show what has been cached and to manually remove values.

@s3inlc
Copy link
Member

s3inlc commented Aug 7, 2023

Thanks for the PR :)
There are a few additional things I noticed:

  • The code style was not consistently applied, there are quite a few functions which have the curly brackets on new lines after function definitions.
  • The new feature should also be documented in doc/changelog.md
  • Probably the TTL should be configurable as different users may have different times they would like to have benchmark results cached (ideally, even add that e.g. if it is set to 0, the caching will be disabled).
  • I tried to test the feature, but it seems that the upgrade process is somehow broken, during initialization it fails with the following error:
hashtopolis-backend     | Start initialization process...
hashtopolis-backend     | PHP Fatal error:  Uncaught PDOException: SQLSTATE[42000]: Syntax error or access violation: 1075 Incorrect table definition; there can be only one auto column and it must be defined as a key in /var/www/html/install/updates/update_v0.14.x_v0.14.0.php:10
hashtopolis-backend     | Stack trace:
hashtopolis-backend     | #0 /var/www/html/install/updates/update_v0.14.x_v0.14.0.php(10): PDO->query()
hashtopolis-backend     | #1 /var/www/html/install/updates/update.php(53): include('...')
hashtopolis-backend     | #2 /var/www/html/inc/load.php(162): include('...')
hashtopolis-backend     | #3 {main}
hashtopolis-backend     |   thrown in /var/www/html/install/updates/update_v0.14.x_v0.14.0.php on line 10

and when accessing the benchmark page it is missing the tables which are commented out in the update script.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While the release is not fixed and in preparation, the update files typically are named ./update_v0.14.x_v0.x.x.php.

ALTER TABLE `Agent`
ADD PRIMARY KEY (`agentId`),
ADD KEY `userId` (`userId`);
-- ADD KEY `hardwareGroupId` (`hardwareGroupId`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this commented out?

@@ -1300,6 +1331,7 @@ ALTER TABLE `AccessGroupUser`

ALTER TABLE `Agent`
ADD CONSTRAINT `Agent_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `User` (`userId`);
-- ADD CONSTRAINT `Agent_ibfk_2` FOREIGN KEY (`hardwareGroupId`) REFERENCES `HardwareGroup` (`hardwareGroupId`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this commented out?

<?php /** @noinspection SqlNoDataSourceInspection */
use DBA\Factory;

if (!Util::databaseTableExists("HardwareGroup")) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typically, we wrap upgrade steps also with in a check of a unique key which is stored in database to determine if the update part was already executed or not. Of course, if databaseTableExists() is checked, it would not execute it twice anyway. But with having a key stored in the database, it's also easier to look up in case of issues and to keep consistency overall, we should always have this wrap with a key (as seen in the other update files).

Factory::getAgentFactory()->getDB()->query("ALTER TABLE `HardwareGroup` ADD PRIMARY KEY (`hardwareGroupId`);");
}

//change Agent table
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this should not be commented out? Otherwise I think this would break existing installations as the Agent table would not be as expected with the benchmark caching code.

The same probably applies for the Benchmark table and the adding of the foreign key constraints.

@jessevz
Copy link
Contributor Author

jessevz commented Aug 11, 2023

@s3inlc thanks for the review! I have changed my updatescript and I think it works properly now. But there is still something that i do not understand, and that is when I delete my docker volumes to make Hashtopolis run my install script, it will also run my update script afterwards which will fail since it will try to make the same tables for the second time. What should I change so that the updatescript doesnt get run after an install?

@s3inlc
Copy link
Member

s3inlc commented Aug 24, 2023

Thanks for the changes and sorry for the waiting time. I tested it more in detail now, there are a few things left which should be fixed which I'll put into the review. Regarding your question for the update script, essentially it's double check, but normally we do the check with the key (as you implemented now) and inside that we do again a check if the table already exists. This then covers all cases of setups from a release, from pulled master, etc.

When I tested the benchmark caching one small point came up. When caching the benchmark it is independent from the agent specific parameters. Though this can have a large influence, e.g. if someone decides to use a machine with multiple GPUs, but e.g. runs multiple agents with one using one of the GPUs each (using -d ). Maybe that is something to consider, that there may be agent specific parameters which should be taken into account as part of the benchmark cache CMD?

Copy link
Member

@s3inlc s3inlc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went over the changes in detail and made comments where things need to be addressed.

if (!$agent) {
UI::printError("ERROR", "Agent not found!");
} else {
$qF = new QueryFilter("agentId", $agent->getId(), "=");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation needed for line 33 and 34


if (isset($_GET['id'])) {
//go to detail page
// Template::loadInstance("benchmark/detail");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is the ID which is retrieved here used as the agent ID? Shouldn't that be the benchmark ID which is queried here and then shown?
When being accessed with benchmark.php?id=xy it will produce internal server errors, because the benchmark table does not have an agentId column.

* @return HardwareGroup
*/
function createObjectFromDict($pk, $dict) {
$o = new HardwareGroup($dict['hardwareGroupId'], $dict['devices'], $dict['benchmarkId']);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be an inconsistency between the model and what is expected here. Maybe this should be re-generated again, as benchmarkId is not existing in the HardwareGroup model.

Factory::getAgentFactory()->mset($this->agent, [
Agent::DEVICES => htmlentities(implode("\n", $devices), ENT_QUOTES, "UTF-8"),
//change to hardware group
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as this gets removed, I would propose to delete it. It will not be needed again later.

@@ -26,6 +26,8 @@ class DAccessControl {
const SERVER_CONFIG_ACCESS = "serverConfigAccess";
const USER_CONFIG_ACCESS = "userConfigAccess";
const MANAGE_ACCESS_GROUP_ACCESS = "manageAccessGroupAccess";
const VIEW_BENCHMARK_ACCESS = "ViewBenchmarkAccess";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would indent the same as with all the other values.

<thead>
<tr>
<th>id</th>
<th>Cmd</th>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would write CMD

<table class="table table-bordered table-sm" id="benchmarks">
<thead>
<tr>
<th>id</th>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would write ID

<th>CPU/GPU</th>
<th>Benchmark value</th>
<th>ttl</th>
<th>action</th>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would write Action

src/benchmark.php Show resolved Hide resolved
<a class="dropdown-item[[menu.isActive('agents_status')]]" href="agentStatus.php">Agent Status</a>
{{ENDIF}}
{{IF [[accessControl.hasPermission([[$DAccessControl::VIEW_BENCHMARK_ACCESS]])]]}}
<a class="dropdown-item[[menu.isActive('Benchmark_cache')]]" href="benchmark.php">Benchmark cache</a>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to keep it consistent, change the value of the menu entry active name to benchmark_cache

@s3inlc
Copy link
Member

s3inlc commented Aug 25, 2023

Thanks for quickly updating all the requested parts. It seems that there now are only some issues with the tests remaining.
One of the agent tests probably fails, because there was the change with the devices: https://github.com/hashtopolis/server/actions/runs/5974589110/job/16211674722?pr=955#step:6:96 and https://github.com/hashtopolis/server/actions/runs/5974589110/job/16211674722?pr=955#step:6:102

And the other one is most likely caused by a missing use statement in the BenchmarkUtils class: https://github.com/hashtopolis/server/actions/runs/5974589110/job/16211674722?pr=955#step:6:121

@jessevz
Copy link
Contributor Author

jessevz commented Aug 26, 2023

I think everything works now, if there are still any improvements that needs to be made please let me know.

what's good to know is that how the attackparameters are parsed is still a bit POC-ish. For example i currently used a static map that parses a few short list parameters and turns them into the long list parameter to make sure the attackparameters are in 1 single format. Ideally we want to have a dynamic map were the cracker binary gives all the possible short and long list parameters, but I thought that would require so many adjustments to the code that it probably had to be a separate story.

@s3inlc
Copy link
Member

s3inlc commented Aug 26, 2023

Thanks for all the updates and addressing all the requested changes. So far it looks now good for me. I will have a final look with zyronix regarding the PR and if we don't see anything else, it should be fine to merge.

Regarding your statement about the way you implemented the parsing of the parameters. I see that the perfect way would be much more complicated with parsing the possible short/long parameter combinations, also if any other cracker comes into place. For the moment I think your solution does cover already most of the cases and we may miss just some cases where it does not use the cached value, but it should not effect functionality, just that a benchmark may be requested where it would not be needed.

@zyronix
Copy link
Member

zyronix commented Oct 3, 2023

@jessevz There are some merge conflicts left before we can merge this one. Could you take a look into this one?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants