Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Add Aperf Stats #187

Merged
merged 1 commit into from
Jun 20, 2024
Merged

Add Aperf Stats #187

merged 1 commit into from
Jun 20, 2024

Conversation

janaknat
Copy link
Contributor

Collect the time it takes the various aperf data types to gather the data and print them to a file. This also adds a tab in the report.

aperf_report_stats.tar.gz

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@janaknat janaknat requested a review from a team as a code owner June 18, 2024 14:51
Copy link
Contributor

@wash-amzn wash-amzn left a comment

Choose a reason for hiding this comment

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

I'm not sure the non-time-series graphs are needed, given how tiny their times are. Once we're capturing the log output, we'll have that information available that way, too.

A good learning here is that process collection time is, by a huge margin, the biggest opportunity for improvement.

src/data.rs Outdated
Comment on lines 97 to 98
pub fn init_data_type(&mut self, param: InitParams) -> Result<u128> {
let start = Instant::now();
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think these functions should be measuring and returning their own time. It should be measured by the caller.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah. Makes sense.

@@ -19,6 +19,7 @@ DataTypes.set('flamegraphs', {name: 'flamegraphs', hideClass: '', trueId: '', ca
DataTypes.set('top_functions', {name: 'topfunctions', hideClass: '', trueId: '', callback: topFunctions});
DataTypes.set('processes', {name: 'processes', hideClass: '', trueId: '', callback: processes});
DataTypes.set('perfstat', {name: 'perfstat', hideClass: '', trueId: '', callback: perfStat});
DataTypes.set('aperfstat', {name: 'aperfstat', hideClass: '', trueId: '', callback: aperfStat});
Copy link
Contributor

Choose a reason for hiding this comment

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

All new data types need to be implemented with support for the hiding of all zeros/N/A graphs, which IIRC also means including support for pairing graphs in side-by-side comparisons.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We use the emptyOrCallback() which does that.

Copy link
Contributor

Choose a reason for hiding this comment

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

Are you sure about that? Your example report disagrees. All of the lines here that don't specify a hideClass and trueId don't support the things I'm saying should be required on all new data types going forward (when possible).

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, the attached report has no graphs at all, which falls into a different category. Still, I'm ~fairly sure that the hideClass and trueId being empty means this does not support the features I am asking for

Copy link
Contributor

Choose a reason for hiding this comment

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

Saw offline that this works, yay

src/lib.rs Outdated
Comment on lines 284 to 291
let collect_time: u64 = datatype.collect_data()? as u64;
let print_time: u64 = datatype.write_to_file()? as u64;
aperf_collect_data
.data
.insert(name.clone() + "-collect", collect_time);
aperf_collect_data
.data
.insert(name.clone() + "-print", print_time);
Copy link
Contributor

@wash-amzn wash-amzn Jun 19, 2024

Choose a reason for hiding this comment

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

Encapsulating the measurements like this can be made more robust by taking advantage of passing a function to a helper

aperf_collect_data.measure(name.clone() + "-collect", |datatype| datatype.collect_data())

I'm sure there's syntax errors in there, but it's just an example

such a measure function can do the timing and the appending of the data to self (aperf_collect_data). It removes the need for repeated timing code and avoids the risk of, for example in this case, of the collect and print times getting mixed up. It's also less code in every place doing this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah. Changed it to have a measure() which does the timing and updates the self.data.

@janaknat janaknat force-pushed the aperf-stats branch 2 times, most recently from a32c1dd to c045f15 Compare June 20, 2024 18:51
src/lib.rs Outdated
Comment on lines 115 to 118
F: Fn(&mut data::DataType) -> Result<()>,
{
let start_time = time::Instant::now();
func(datatype)?;
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you not just have this be generic, taking a no-args function and executing it?

That should be possible. The caller creates a lambda that captures everything.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah. Changing it.

src/lib.rs Outdated
Comment on lines 269 to 276
aperf_collect_data.measure(
name.clone() + "-print",
|d: &mut data::DataType| -> Result<()> {
d.write_to_file()?;
Ok(())
},
datatype,
)?;
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this should be able to be

aperf_collect_data.measure(
    name.clone() + "-print",
    || -> Result<()> {
        d.write_to_file()
    }
);

if measure() is made to take a no-args function. I guess it would still have to be typed to return Result<()> since we do have to keep failure handling working

Collect the time it takes the various aperf data types to gather the
data and print them to a file. This also adds a tab in the report.
Comment on lines +118 to +121
func()?;
let func_time: u64 = (time::Instant::now() - start_time).as_micros() as u64;
self.data.insert(name, func_time);
Ok(())
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be slightly better here to record the time even in failure cases, like

let res = func();
// get and store time taken
res

@janaknat janaknat merged commit a05d7ee into main Jun 20, 2024
8 checks passed
@janaknat janaknat deleted the aperf-stats branch June 20, 2024 21:07
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants