Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 63 additions & 6 deletions src/edu/csus/ecs/pc2/clics/API202306/JSON202306Utilities.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 1989-2025 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau.
// Copyright (C) 1989-2026 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau.
package edu.csus.ecs.pc2.clics.API202306;

import java.text.SimpleDateFormat;
Expand Down Expand Up @@ -43,6 +43,8 @@ public class JSON202306Utilities extends JSONUtilities {

public static final String ORGANIZATION_KEY = "organizations";

public static final String PC2_SUBMISSION_ID_KEY = "pc2_submission_id";

public static final String JSON_ANNOTATION_INTERFACE = ".JsonProperty";

/**
Expand Down Expand Up @@ -163,13 +165,14 @@ public String stringOuterChars(String string, char start, char end ) {
}

/**
* Add an event prefix to the buffer.
*
* Add an event prefix to a buffer.
* Adds event, (event) id, and data keyword to string.
*
* @param stringBuilder
* @param eventType
* @param data - json data for object
* @param eventName Event (notification) type, eg. "submissions", "judgements", etc.
* @param eventSequence Used for generating the token
* @param id ID for this event
* @param data The data associated with the event
* @return Json formatted string containing the full notification
*/
public String getJSONEvent(String eventName, long eventSequence, String id, String data) {
StringBuilder stringBuilder = new StringBuilder();
Expand Down Expand Up @@ -203,4 +206,58 @@ public void appendJSONEvent(StringBuilder stringBuilder, String eventName, long

}

/**
* Add an event prefix to a buffer, optionally including a custom notification property in the
* event notification prefix.
* Adds event, (event) id, customProperty (an customValue) (if non-null) and data keyword to string.
*
* @param eventName Event (notification) type, eg. "judgements", "submissions", etc.
* @param eventSequence Sequence number used for generating the token
* @param id Event ID
* @param data The data property of the event
* @param customProperty included if non-null (it's optional)
* @param customValue value for customProperty, if customProperty is non-null
* @return Json formatted string containing the full notification
*/
public String getJSONEvent(String eventName, long eventSequence, String id, String data,
String customProperty, String customValue) {
Comment thread
clevengr marked this conversation as resolved.
StringBuilder stringBuilder = new StringBuilder();
appendJSONEvent(stringBuilder, eventName, eventSequence, id, data, customProperty, customValue);
return stringBuilder.toString();
}

public void appendJSONEvent(StringBuilder stringBuilder, String eventName, long eventSequence, String id, String data,
String customProperty, String customValue) {

// {"type": "<event type>", "token": "<token>", "id": "<id>", "op": "<type of operation>", "data": <JSON data for element>, "customProperty": <customValue> }

stringBuilder.append("{");
appendPair(stringBuilder, "type", eventName);
stringBuilder.append(",");

appendPair(stringBuilder, "token", EventFeedJSON.getEventId(eventSequence));
stringBuilder.append(",");

if(id == null) {
appendPairNullValue(stringBuilder, "id");
} else {
appendPair(stringBuilder, "id", id);
}
stringBuilder.append(",");

stringBuilder.append("\"data\": ");

stringBuilder.append(data);

// Check if this is a "judgements" delete notification, if so, add PC2 custom property indicating
// the submission id
if(customProperty != null) {
stringBuilder.append(",\"");
stringBuilder.append(customProperty);
stringBuilder.append("\": ");
// null is safe here
stringBuilder.append(customValue);
}
}

}
18 changes: 14 additions & 4 deletions src/edu/csus/ecs/pc2/core/execute/ExecutionData.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 1989-2025 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau.
// Copyright (C) 1989-2026 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau.
package edu.csus.ecs.pc2.core.execute;

import java.io.Serializable;
Expand Down Expand Up @@ -55,6 +55,8 @@ public class ExecutionData implements Serializable {

private long executeTimeMS = 0;

private long maxExecuteTimeMS = 0;

private long validateTimeMS = 0;

private Exception executionException = null;
Expand All @@ -66,7 +68,7 @@ public class ExecutionData implements Serializable {
private boolean failedToCompile = false;

private String additionalInformation = "";

//fields associated with "point-scoring" contests
private double score ;
private CLICS_JUDGEMENT_ACRONYM judgementAcronym ;
Expand Down Expand Up @@ -293,12 +295,20 @@ public long getCompileTimeMS() {

public void setExecuteTimeMS(long inExecuteTime){
executeTimeMS = inExecuteTime;
// Keep track of longest execution time

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If I recall correctly how the code works, there is a separate ExecutionData object associated with the execution of each test case. If that's true, it doesn't seem logical to me to be storing the "longest execution time" in the ExecutionData object since each such object relates to (only) one test case execution. Rather, it seems like "longest execution time" should be stored in some higher-level object that associated with the entire sequence of test case executions. Am I mis-remembering how the code is structured?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Recall I wrote up a document explaining how ExecutionData is used. Here is a link: PC2 Execution Data Class
That should explain it. In a nutshell, the "per-test-case" execution information is only part of what is stored in ExecutionData. Compile results, and the final judgment for the Run is stored in there as well and examined by the caller to determine the disposition of the Run.

if(executeTimeMS > maxExecuteTimeMS) {
maxExecuteTimeMS = executeTimeMS;
}
}

public long getExecuteTimeMS(){
return executeTimeMS;
}

public long getMaxExecuteTimeMS() {
return maxExecuteTimeMS;
}

public void setvalidateTimeMS(long validateTime){
validateTimeMS = validateTime;
}
Expand Down Expand Up @@ -415,7 +425,7 @@ public String toString() {

return retStr;
}

/**
* When the same execute data is to be used between successive test cases, certain fields should be reset.
* Specifically, those related to the actual execution and validation of the test case run.
Expand All @@ -439,7 +449,7 @@ public void ResetExecuteCallResults() {
memoryLimitExceeded = false;
failedToCompile = false;
additionalInformation = "";

//fields associated with "point-scoring" contests
double score = 0;
CLICS_JUDGEMENT_ACRONYM judgementAcronym = null;
Expand Down
10 changes: 5 additions & 5 deletions src/edu/csus/ecs/pc2/ui/AutoJudgingMonitor.java
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 1989-2025 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau.
// Copyright (C) 1989-2026 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau.
package edu.csus.ecs.pc2.ui;

import java.util.ArrayList;
Expand Down Expand Up @@ -610,12 +610,12 @@ private void executeAndAutoJudgeRun() {

judgementRecord = new JudgementRecord(elementId, contest.getClientId(), solved, true, true);
judgementRecord.setValidatorResultString(results);

//if it's a point-scoring contest, put the score and the judgement into the JudgementRecord
if (contest.getContestInformation().isScoreboardTypeScore()) {

judgementRecord.setScore(executionData.getScore());

CLICS_JUDGEMENT_ACRONYM acronym = executionData.getJudgementAcronym();
String judgementDescription ;
if (acronym != null) {
Expand Down Expand Up @@ -668,7 +668,7 @@ private void executeAndAutoJudgeRun() {
long milliDiff = cal.getTime().getTime() - startTimeCalendar.getTime().getTime();
long totalSeconds = milliDiff / 1000;
judgementRecord.setHowLongToJudgeInSeconds(totalSeconds);
judgementRecord.setExecuteMS(executeTimeMS);
judgementRecord.setExecuteMS(executionData.getMaxExecuteTimeMS());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The name of the setter now seems inappropriate; it's no longer setting an "execution time", it's setting a "maximum execution time over all the test cases".

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The comment in JudgementRecord says, "Number of seconds it took to execute the run." Aside from the comment specifying the incorrect units (seconds, vs. MS), before this PR, that value was essentially meaningless (it was the execute time of the LAST test case). Now, it contains what I believe to be the original intent which is the time of the longest test case, since this value is used in the ViewJudgementsPane as the "X time", indicating (I would imagine) maximum execute time. What else could it possibly be? The "X time" column was added in 2011 by Doug:

bug 668: now sets the ms for the execute time into the system.
Shows on reports, added column to View Judgement X time for execute time in ms.

svn path=/trunk/; revision=2419

Keep in mind that JudgementRecord is different than ExecutionData. JudgementRecord is created from the information in ExecutionData. (ref. core.execute.JudgementUtilities.createJudgementRecord(...))

judgementRecord.setJudgeStartDate(fetchedRun.getJudgeStartDate());

runResultFiles = new RunResultFiles(fetchedRun, fetchedRun.getProblemId(), judgementRecord, executable.getExecutionData());
Expand Down
31 changes: 15 additions & 16 deletions src/edu/csus/ecs/pc2/ui/SelectJudgementPaneNew.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// Copyright (C) 1989-2025 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau.
// Copyright (C) 1989-2026 PC2 Development Team: John Clevenger, Douglas Lane, Samir Ashoo, and Troy Boudreau.
package edu.csus.ecs.pc2.ui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Frame;
Expand All @@ -28,7 +29,6 @@
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.border.TitledBorder;
Expand Down Expand Up @@ -63,7 +63,6 @@
import edu.csus.ecs.pc2.core.model.SerializedFile;
import edu.csus.ecs.pc2.core.security.Permission;
import edu.csus.ecs.pc2.ui.judge.JudgeView;
import java.awt.Dimension;

/**
* Select a Judgement Pane.
Expand Down Expand Up @@ -157,7 +156,7 @@ public class SelectJudgementPaneNew extends JPanePlugin {
private JLabel validatorAnswer = null;

private JLabel selectJudgementCheckboxLabel = null;

private JButton viewOutputsAndDataButton = null;

private GregorianCalendar startTimeCalendar;
Expand Down Expand Up @@ -191,7 +190,7 @@ public class SelectJudgementPaneNew extends JPanePlugin {
private JLabel additionalInfoTextLabel;

private JLabel addtionalInfoMoreButtonLabel;

private boolean isPointScoring = false;

/**
Expand Down Expand Up @@ -224,9 +223,9 @@ private void initialize() {
@Override
public void setContestAndController(IInternalContest inContest, IInternalController inController) {
super.setContestAndController(inContest, inController);

isPointScoring = inContest.getContestInformation().isScoreboardTypeScore();

log = getController().getLog();

displayTeamName = new DisplayTeamName();
Expand Down Expand Up @@ -412,7 +411,7 @@ protected void updateRun() {
if (executable != null) {
executionData = executable.getExecutionData();
if (judgementRecord != null) {
judgementRecord.setExecuteMS(executionData.getExecuteTimeMS());
judgementRecord.setExecuteMS(executionData.getMaxExecuteTimeMS());
Comment thread
clevengr marked this conversation as resolved.
judgementRecord.setScore(executionData.getScore());
}
}
Expand Down Expand Up @@ -539,7 +538,7 @@ private void populateGUI(Run theRun) {
// if there IS a computer judgement, try to find a corresponding RunResultFile record
RunResultFiles matchingResult = null;
if (computerJudgement != null) {

// search the RunResultFiles array for a matching result
if (runResultFiles != null) {
for (int i = 0; i < runResultFiles.length; i++) {
Expand Down Expand Up @@ -887,7 +886,7 @@ protected void extractRun() {
* Takes a boolean condition whether to override stop on first failure condition
*/
protected void executeRun(boolean overrideStopOnFirstFailedTestCase) {

executeTimeMS = 0;
System.gc();

Expand Down Expand Up @@ -957,7 +956,7 @@ protected void executeRun(boolean overrideStopOnFirstFailedTestCase) {
getTestResultsFrame().setData(run, runFiles, problem, getProblemDataFiles());
getTestResultsFrame().setVisible(true);
}
executeTimeMS = executable.getExecutionData().getExecuteTimeMS();
executeTimeMS = executable.getExecutionData().getMaxExecuteTimeMS();

// Show validator results, if there are any.

Expand Down Expand Up @@ -1002,12 +1001,12 @@ protected void executeRun(boolean overrideStopOnFirstFailedTestCase) {

judgementRecord = new JudgementRecord(elementId, run.getSubmitter(), solved, true);
judgementRecord.setValidatorResultString(results);

//if it's a point-scoring contest, put the score and the judgement into the JudgementRecord
if (isPointScoring) {

judgementRecord.setScore(executionData.getScore());

CLICS_JUDGEMENT_ACRONYM acronym = executionData.getJudgementAcronym();
String judgementDescription ;
if (acronym != null) {
Expand Down Expand Up @@ -1458,7 +1457,7 @@ private void showValidatorControls(boolean showControls) {
if (executionData != null) {
String additionalText = null;
boolean enableMoreButton = false;

if (isPointScoring && executionData.getJudgementAcronym() == CLICS_JUDGEMENT_ACRONYM.AC) {
DecimalFormat df = new DecimalFormat("0.0###");
additionalText = "Score: " + df.format(executionData.getScore());
Expand Down Expand Up @@ -1563,7 +1562,7 @@ protected void acceptValidatorJudgement() {
// this will be null if we are accepting the computer judgement
if (executable != null) {
executionData = executable.getExecutionData();
judgementRecord.setExecuteMS(executionData.getExecuteTimeMS());
judgementRecord.setExecuteMS(executionData.getMaxExecuteTimeMS());
Comment thread
clevengr marked this conversation as resolved.
judgementRecord.setScore(executionData.getScore());
}
newRunResultFiles = new RunResultFiles(newRun, newRun.getProblemId(), judgementRecord, executionData);
Expand Down
Loading