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

Add support for timing steps and pipelines #613

Merged
merged 43 commits into from
Oct 31, 2016

Conversation

SamCarlberg
Copy link
Member

@SamCarlberg SamCarlberg commented Jul 7, 2016

This lets users know which parts of their pipelines take the most time, and how long the pipeline takes as a whole.

timing-and-analysis.png

@@ -59,6 +66,7 @@
private Pane aboutPane;
@FXML
private StatusBar statusBar;
private Label elapsedTimeLabel; // TODO improve the layout of this label
Copy link
Member Author

Choose a reason for hiding this comment

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

This label isn't centered vertically in the status bar, and it separates the start/stop button from the "Pipeline STATE" text.

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 move the Pipeline status into its own label and then center both (i.e. do not use statusBar.setText() for the status)

@SamCarlberg
Copy link
Member Author

SamCarlberg commented Jul 7, 2016

It may also be a good idea to collect the timing data and have a UI for displaying statistics about each operation, such as

  • Mean runtime
  • Median runtime
  • Relative mean runtime (% of overall time the mean runtime takes)
  • Relative median runtime (% of overall time the median runtime takes)

And statistics about the pipeline

  • GRIP overhead (% of time spent not running any operation)
  • Hotspot operations (those that run > 1 standard deviation above mean run time)

So for the pipeline pictured in the top comment,

  • GRIP overhead is 2.5%
  • Mean operation runtime is 5.03ms (s = 6.39ms)
  • Blur is a big hotspot (two standard deviations above mean)

@codecov-io
Copy link

codecov-io commented Jul 7, 2016

Current coverage is 54.25% (diff: 51.56%)

Merging #613 into master will decrease coverage by 0.22%

@@             master       #613   diff @@
==========================================
  Files           209        218     +9   
  Lines          6713       7067   +354   
  Methods           0          0          
  Messages          0          0          
  Branches        656        697    +41   
==========================================
+ Hits           3657       3834   +177   
- Misses         2886       3062   +176   
- Partials        170        171     +1   

Sunburst

Powered by Codecov. Last update 1d02ed1...3d7481c

@JLLeitschuh
Copy link
Member

Can you maybe put those stats in the right side of the status bar?

@SamCarlberg
Copy link
Member Author

SamCarlberg commented Jul 7, 2016

I think it makes more sense on the left side, that stuff is all related and it makes sense to keep them together. It's also not great for UX to put it on the right side

@@ -46,6 +53,8 @@
@FXML
private Labeled title;
@FXML
private Label elapsedTime;
Copy link
Member

Choose a reason for hiding this comment

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

You can fix it in the fxml with padding

// >1: error
private static final double alpha = 0.35;

private final ExponentialMovingAverage ema = new ExponentialMovingAverage(alpha);
Copy link
Member Author

Choose a reason for hiding this comment

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

Maybe change this to a normal arithmetic moving average, the output of this still isn't very consistent.

@AustinShalit
Copy link
Member

AustinShalit commented Jul 10, 2016

When I open the analysis window I get a stack overflow: pastebin

Looks like it happens when I click and drag the window.

@SamCarlberg
Copy link
Member Author

Does it only happen when you move the window?

@AustinShalit
Copy link
Member

AustinShalit commented Jul 11, 2016

Here is another log and a video:

http://pastebin.com/JinS2Frq
https://youtu.be/BcppMd6XX-Q

@SamCarlberg
Copy link
Member Author

That looks like a JavaFX bug to me

checkNotNull(data, "data");
this.source = source;
this.elapsedTime = elapsedTime;
this.data = data;
Copy link
Member

Choose a reason for hiding this comment

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

checkNotNull(source, "source"); returns the source so you can just use it in the same line as the assignment.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is cleaner IMO

@SamCarlberg
Copy link
Member Author

Can you add the column with the results from the last benchmark??

I think I'll make it CSV in a TextArea to make it easy to import into stuff like excel and google sheets

@AustinShalit AustinShalit modified the milestones: v1.5.0, 1.6.0 Aug 27, 2016
Copy link
Member

@JLLeitschuh JLLeitschuh left a comment

Choose a reason for hiding this comment

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

The places that I'm not totally clear what's going on could use some inline documentation.
I'd rather avoid using instanceof if possible. Can you try to avoid that.

* @param o2 the second step to compare
*/
@Override
default int compare(Step o1, Step o2) {
Copy link
Member

Choose a reason for hiding this comment

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

Interesting solution.

started();
target.run();
} finally {
stopped();
Copy link
Member

Choose a reason for hiding this comment

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

Do you want to catch any potential exceptions this may throw?

Copy link
Member Author

Choose a reason for hiding this comment

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

No, exceptions are propagated up the stack and are caught.

* @throws IllegalStateException if this a call to this method is not preceded by a call to
* {@link #started()}.
*/
public synchronized void stopped() {
Copy link
Member

Choose a reason for hiding this comment

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

Should this be renamed stop?
Its an action, stopped infers a question.

analysisStage.setOnCloseRequest(event -> eventBus.post(BenchmarkEvent.finished()));
eventBus.register(controller);
analysisStage.showAndWait();
eventBus.unregister(controller); // unregister to avoid memory leak
Copy link
Member

Choose a reason for hiding this comment

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

How does this work on a high DPI screen?
The fonts get all weird on those sort of screens.

sb.append(stddev.get(i));
sb.append('\n');
}
return sb.toString();
Copy link
Member

Choose a reason for hiding this comment

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

Are you sure this is correctly formatted CSV?
This isn't using a library to create CSV and there aren't any tests for this code.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes it is

Copy link
Member

Choose a reason for hiding this comment

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

I have a plugin from codecov that shows me in the PR what code is covered and what isn't.
This isn't covered by tests.
https://chrome.google.com/webstore/detail/codecov-extension/keefkhehidemnokodkdkejapdgfjmijf/related

@@ -192,6 +206,25 @@ private void moveStepRight() {
pipeline.moveStep(step, +1);
}

@Subscribe
@SuppressWarnings("PMD.UnusedPrivateMethod")
Copy link
Member

Choose a reason for hiding this comment

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

There must be a way to disable this error when there is this annotation on the method.
Not sure how to do it.

final String formatStyle = "-fx-accent: hsb(%.2f, 100%%, 100%%);";
progressBar.setStyle(String.format(formatStyle, h));
} else {
progressBar.setStyle("-fx-accent: hsb(180, 100%, 75%);"); // blue-gray
Copy link
Member

Choose a reason for hiding this comment

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

Want to use css classes to do this?

table.setItems(tableItems);

benchmarkRunsField.textProperty().addListener((observable, oldValue, newValue) -> {
if ((oldValue.isEmpty() && "0".equals(newValue)) || !newValue.matches("[\\d]*")) {
Copy link
Member

Choose a reason for hiding this comment

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

What is this regex checking?

Copy link
Member Author

Choose a reason for hiding this comment

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

Checks if the input is a number

@Subscribe
@SuppressWarnings({"PMD.UnusedPrivateMethod", "PMD.UnusedFormalParameter"})
private void runStopped(TimerEvent event) {
if (!(event.getTarget() instanceof PipelineRunner)) {
Copy link
Member

Choose a reason for hiding this comment

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

instanceof is bad practice. What are you trying to do here?
Can you do something different here?

@Subscribe
@SuppressWarnings("PMD.UnusedPrivateMethod")
private void onRun(TimerEvent event) {
if (event.getTarget() instanceof Step) {
Copy link
Member

Choose a reason for hiding this comment

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

Can you avoid this instance of check?

Copy link
Member

Choose a reason for hiding this comment

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

Why do you need to do this instanceof check?

@AustinShalit AustinShalit modified the milestones: 1.6.0, v1.5.0 Oct 5, 2016
/**
* Gets the number of samples.
*/
public int getN() {
Copy link
Member

Choose a reason for hiding this comment

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

Can this be something like sampleCount or number or dataPoints? getN seems ambiguous.

Copy link
Member

@JLLeitschuh JLLeitschuh left a comment

Choose a reason for hiding this comment

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

Just a few things.
Also, can you do something other than that instanceof check?

private final int n;
private final double sum;
private final double mean;
private final double s;
Copy link
Member

Choose a reason for hiding this comment

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

Can you rename this to something like sqrt?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's the standard deviation, s is a standard symbol

* </code></pre>
* </p>
*/
public class Timer {
Copy link
Member

Choose a reason for hiding this comment

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

Annotate with @ThreadSafe?

* @param value the value to calculate the hotness of
* @return the hotness of the given value.
*/
public double hotness(double value) {
Copy link
Member

@JLLeitschuh JLLeitschuh Oct 6, 2016

Choose a reason for hiding this comment

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

What is the range of hotness values? 0-10? 0 to 1? This should be documented.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hotness can be any number >= 0. The current implementation is just the number of standard deviations above the mean

Copy link
Member

Choose a reason for hiding this comment

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

How do you represent hotness on the UI? What is the scale? What is the max value of the UI?

Copy link
Member Author

Choose a reason for hiding this comment

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

Hotness is represented by the hue of the bar. The length of the bar represents what percentage of time the step takes. Hotness values over three standard deviations are clamped to avoid having high-sigma steps having the same color as low-sigma steps.

Copy link
Member

Choose a reason for hiding this comment

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

Can you document that a little bit better in the javadoc?

Imagine I don't understand statistics and want to use this class. :p

@JLLeitschuh
Copy link
Member

JLLeitschuh commented Oct 31, 2016

@SamCarlberg SamCarlberg merged commit 31e6b93 into WPIRoboticsProjects:master Oct 31, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants