summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorgios Andreadis <g.andreadis@student.tudelft.nl>2017-09-21 10:20:50 +0200
committerGeorgios Andreadis <g.andreadis@student.tudelft.nl>2017-09-23 10:06:04 +0200
commitda861719c6433a1fc9346da958f0907e52d578ce (patch)
treeb171796fbfe17f0356bf6e32430223c67812a760
parentf8f617c97fcb2df3dbefc9527d974151e367cb60 (diff)
Show experiment and trace data on left-hand sidebar
-rw-r--r--src/components/sidebars/simulation/ExperimentMetadataComponent.js12
-rw-r--r--src/components/sidebars/simulation/SimulationSidebarComponent.js21
-rw-r--r--src/components/sidebars/simulation/SimulationSidebarComponent.sass8
-rw-r--r--src/components/sidebars/simulation/TaskComponent.js31
-rw-r--r--src/components/sidebars/simulation/TraceComponent.js17
-rw-r--r--src/components/timeline/Timeline.js15
-rw-r--r--src/components/timeline/TimelineComponent.js43
-rw-r--r--src/containers/sidebars/simulation/ExperimentMetadataContainer.js29
-rw-r--r--src/containers/sidebars/simulation/TaskContainer.js23
-rw-r--r--src/containers/sidebars/simulation/TraceContainer.js22
-rw-r--r--src/containers/timeline/TimelineContainer.js37
-rw-r--r--src/containers/timeline/TimelineControlsContainer.js4
-rw-r--r--src/pages/App.js9
-rw-r--r--src/reducers/construction-mode.js3
-rw-r--r--src/reducers/interaction-level.js7
-rw-r--r--src/reducers/modals.js2
-rw-r--r--src/reducers/simulation-mode.js9
-rw-r--r--src/sagas/experiments.js28
18 files changed, 301 insertions, 19 deletions
diff --git a/src/components/sidebars/simulation/ExperimentMetadataComponent.js b/src/components/sidebars/simulation/ExperimentMetadataComponent.js
new file mode 100644
index 00000000..26383d6a
--- /dev/null
+++ b/src/components/sidebars/simulation/ExperimentMetadataComponent.js
@@ -0,0 +1,12 @@
+import React from "react";
+
+const ExperimentMetadataComponent = ({experimentName, pathName, traceName, schedulerName}) => (
+ <div>
+ <h2>{experimentName}</h2>
+ <p><strong>Path:</strong> {pathName}</p>
+ <p><strong>Trace:</strong> {traceName}</p>
+ <p><strong>Scheduler:</strong> {schedulerName}</p>
+ </div>
+);
+
+export default ExperimentMetadataComponent;
diff --git a/src/components/sidebars/simulation/SimulationSidebarComponent.js b/src/components/sidebars/simulation/SimulationSidebarComponent.js
new file mode 100644
index 00000000..7da064c4
--- /dev/null
+++ b/src/components/sidebars/simulation/SimulationSidebarComponent.js
@@ -0,0 +1,21 @@
+import React from "react";
+import ExperimentMetadataContainer from "../../../containers/sidebars/simulation/ExperimentMetadataContainer";
+import TraceContainer from "../../../containers/sidebars/simulation/TraceContainer";
+import Sidebar from "../Sidebar";
+import "./SimulationSidebarComponent.css";
+
+const SimulationSidebarComponent = () => {
+ return (
+ <Sidebar isRight={false}>
+ <div className="simulation-sidebar-container flex-column">
+ <ExperimentMetadataContainer/>
+ <hr/>
+ <div className="trace-container">
+ <TraceContainer/>
+ </div>
+ </div>
+ </Sidebar>
+ );
+};
+
+export default SimulationSidebarComponent;
diff --git a/src/components/sidebars/simulation/SimulationSidebarComponent.sass b/src/components/sidebars/simulation/SimulationSidebarComponent.sass
new file mode 100644
index 00000000..82af97fa
--- /dev/null
+++ b/src/components/sidebars/simulation/SimulationSidebarComponent.sass
@@ -0,0 +1,8 @@
+.simulation-sidebar-container
+ display: flex
+ height: 100%
+ max-height: 100%
+
+.trace-container
+ flex: 1
+ overflow-y: scroll
diff --git a/src/components/sidebars/simulation/TaskComponent.js b/src/components/sidebars/simulation/TaskComponent.js
new file mode 100644
index 00000000..9a26e720
--- /dev/null
+++ b/src/components/sidebars/simulation/TaskComponent.js
@@ -0,0 +1,31 @@
+import React from "react";
+import {convertSecondsToFormattedTime} from "../../../util/date-time";
+
+const TaskComponent = ({task, flopsLeft}) => {
+ let stateInfo;
+
+ if (flopsLeft === task.totalFlopCount) {
+ stateInfo = <p><span className="fa fa-hourglass-half"/>Waiting</p>;
+ } else if (flopsLeft > 0) {
+ stateInfo = (
+ <p>
+ <span className="fa fa-refresh"/>
+ Running ({task.totalFlopCount - flopsLeft} / {task.totalFlopCount} FLOPS)
+ </p>
+ );
+ } else {
+ stateInfo = <p><span className="fa fa-check"/>Completed</p>;
+ }
+
+ return (
+ <li className="list-group-item flex-column align-items-start">
+ <div className="d-flex w-100 justify-content-between">
+ <h5 className="mb-1">{task.totalFlopCount} FLOPS</h5>
+ <small>Starts: {convertSecondsToFormattedTime(task.startTick)}</small>
+ </div>
+ {stateInfo}
+ </li>
+ );
+};
+
+export default TaskComponent;
diff --git a/src/components/sidebars/simulation/TraceComponent.js b/src/components/sidebars/simulation/TraceComponent.js
new file mode 100644
index 00000000..498fe5bf
--- /dev/null
+++ b/src/components/sidebars/simulation/TraceComponent.js
@@ -0,0 +1,17 @@
+import React from "react";
+import TaskContainer from "../../../containers/sidebars/simulation/TaskContainer";
+
+const TraceComponent = ({jobs}) => (
+ <div>
+ <h3>Trace</h3>
+ {jobs.map(job => (
+ <ul className="list-group" key={job.id}>
+ {job.taskIds.map(taskId => (
+ <TaskContainer taskId={taskId} key={taskId}/>
+ ))}
+ </ul>
+ ))}
+ </div>
+);
+
+export default TraceComponent;
diff --git a/src/components/timeline/Timeline.js b/src/components/timeline/Timeline.js
deleted file mode 100644
index a2a858eb..00000000
--- a/src/components/timeline/Timeline.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import React from "react";
-import TimelineControlsContainer from "../../containers/timeline/TimelineControlsContainer";
-import TimelineLabelsContainer from "../../containers/timeline/TimelineLabelsContainer";
-import "./Timeline.css";
-
-const Timeline = ({currentTick, lastSimulatedTick}) => (
- <div className="timeline-bar">
- <div className="timeline-container">
- <TimelineLabelsContainer/>
- <TimelineControlsContainer/>
- </div>
- </div>
-);
-
-export default Timeline;
diff --git a/src/components/timeline/TimelineComponent.js b/src/components/timeline/TimelineComponent.js
new file mode 100644
index 00000000..b400a378
--- /dev/null
+++ b/src/components/timeline/TimelineComponent.js
@@ -0,0 +1,43 @@
+import React from "react";
+import TimelineControlsContainer from "../../containers/timeline/TimelineControlsContainer";
+import TimelineLabelsContainer from "../../containers/timeline/TimelineLabelsContainer";
+import "./Timeline.css";
+
+class TimelineComponent extends React.Component {
+ componentDidMount() {
+ this.interval = setInterval(() => {
+ if (!this.props.isPlaying) {
+ return;
+ }
+
+ if (this.props.currentTick < this.props.lastSimulatedTick) {
+ for (let i in this.props.sections.reverse()) {
+ if (this.props.currentTick + 1 >= this.props.sections[i].startTick) {
+ if (this.props.currentDatacenterId !== this.props.sections[i].datacenterId) {
+ this.props.setCurrentDatacenter(this.props.sections[i].datacenterId);
+ }
+ break;
+ }
+ }
+ this.props.incrementTick();
+ }
+ }, 1000);
+ }
+
+ componentWillUnmount() {
+ clearInterval(this.interval);
+ }
+
+ render() {
+ return (
+ <div className="timeline-bar">
+ <div className="timeline-container">
+ <TimelineLabelsContainer/>
+ <TimelineControlsContainer/>
+ </div>
+ </div>
+ );
+ }
+}
+
+export default TimelineComponent;
diff --git a/src/containers/sidebars/simulation/ExperimentMetadataContainer.js b/src/containers/sidebars/simulation/ExperimentMetadataContainer.js
new file mode 100644
index 00000000..55323f11
--- /dev/null
+++ b/src/containers/sidebars/simulation/ExperimentMetadataContainer.js
@@ -0,0 +1,29 @@
+import {connect} from "react-redux";
+import ExperimentMetadataComponent from "../../../components/sidebars/simulation/ExperimentMetadataComponent";
+
+const mapStateToProps = state => {
+ if (!state.objects.experiment[state.currentExperimentId]) {
+ return {
+ experimentName: "Loading experiment",
+ pathName: "",
+ traceName: "",
+ schedulerName: "",
+ }
+ }
+
+ const path = state.objects.path[state.objects.experiment[state.currentExperimentId].pathId];
+ const pathName = path.name ? path.name : "Path " + path.id;
+
+ return {
+ experimentName: state.objects.experiment[state.currentExperimentId].name,
+ pathName,
+ traceName: state.objects.trace[state.objects.experiment[state.currentExperimentId].traceId].name,
+ schedulerName: state.objects.scheduler[state.objects.experiment[state.currentExperimentId].schedulerName].name,
+ };
+};
+
+const ExperimentMetadataContainer = connect(
+ mapStateToProps
+)(ExperimentMetadataComponent);
+
+export default ExperimentMetadataContainer;
diff --git a/src/containers/sidebars/simulation/TaskContainer.js b/src/containers/sidebars/simulation/TaskContainer.js
new file mode 100644
index 00000000..df06b5b8
--- /dev/null
+++ b/src/containers/sidebars/simulation/TaskContainer.js
@@ -0,0 +1,23 @@
+import {connect} from "react-redux";
+import TaskComponent from "../../../components/sidebars/simulation/TaskComponent";
+
+const mapStateToProps = (state, ownProps) => {
+ let flopsLeft = state.objects.task[ownProps.taskId].totalFlopCount;
+
+ if (state.states.task[state.currentTick] && state.states.task[state.currentTick][ownProps.taskId]) {
+ flopsLeft = state.states.task[state.currentTick][ownProps.taskId].flopsLeft;
+ } else if (state.objects.task[ownProps.taskId].startTick < state.currentTick) {
+ flopsLeft = 0;
+ }
+
+ return {
+ task: state.objects.task[ownProps.taskId],
+ flopsLeft,
+ };
+};
+
+const TaskContainer = connect(
+ mapStateToProps
+)(TaskComponent);
+
+export default TaskContainer;
diff --git a/src/containers/sidebars/simulation/TraceContainer.js b/src/containers/sidebars/simulation/TraceContainer.js
new file mode 100644
index 00000000..6539823d
--- /dev/null
+++ b/src/containers/sidebars/simulation/TraceContainer.js
@@ -0,0 +1,22 @@
+import {connect} from "react-redux";
+import TraceComponent from "../../../components/sidebars/simulation/TraceComponent";
+
+const mapStateToProps = state => {
+ if (!state.objects.experiment[state.currentExperimentId] ||
+ !state.objects.trace[state.objects.experiment[state.currentExperimentId].traceId].jobIds) {
+ return {
+ jobs: []
+ };
+ }
+
+ return {
+ jobs: state.objects.trace[state.objects.experiment[state.currentExperimentId].traceId].jobIds
+ .map(id => state.objects.job[id]),
+ };
+};
+
+const TraceContainer = connect(
+ mapStateToProps
+)(TraceComponent);
+
+export default TraceContainer;
diff --git a/src/containers/timeline/TimelineContainer.js b/src/containers/timeline/TimelineContainer.js
new file mode 100644
index 00000000..32756b6d
--- /dev/null
+++ b/src/containers/timeline/TimelineContainer.js
@@ -0,0 +1,37 @@
+import {connect} from "react-redux";
+import {incrementTick} from "../../actions/simulation/tick";
+import {setCurrentDatacenter} from "../../actions/topology/building";
+import TimelineComponent from "../../components/timeline/TimelineComponent";
+
+const mapStateToProps = state => {
+ let sections = [];
+ if (state.currentExperimentId !== -1) {
+ const sectionIds = state.objects.path[state.objects.experiment[state.currentExperimentId].pathId].sectionIds;
+
+ if (sectionIds) {
+ sections = sectionIds.map(sectionId => state.objects.section[sectionId]);
+ }
+ }
+
+ return {
+ isPlaying: state.isPlaying,
+ currentTick: state.currentTick,
+ lastSimulatedTick: state.lastSimulatedTick,
+ currentDatacenterId: state.currentDatacenterId,
+ sections,
+ };
+};
+
+const mapDispatchToProps = dispatch => {
+ return {
+ incrementTick: () => dispatch(incrementTick()),
+ setCurrentDatacenter: id => dispatch(setCurrentDatacenter(id))
+ };
+};
+
+const TimelineContainer = connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(TimelineComponent);
+
+export default TimelineContainer;
diff --git a/src/containers/timeline/TimelineControlsContainer.js b/src/containers/timeline/TimelineControlsContainer.js
index e5c89060..1afd336a 100644
--- a/src/containers/timeline/TimelineControlsContainer.js
+++ b/src/containers/timeline/TimelineControlsContainer.js
@@ -5,7 +5,9 @@ const mapStateToProps = state => {
let sectionTicks = [];
if (state.currentExperimentId !== -1) {
const sectionIds = state.objects.path[state.objects.experiment[state.currentExperimentId].pathId].sectionIds;
- sectionTicks = sectionIds.map(sectionId => state.objects.section[sectionId].startTick);
+ if (sectionIds) {
+ sectionTicks = sectionIds.map(sectionId => state.objects.section[sectionId].startTick);
+ }
}
return {
diff --git a/src/pages/App.js b/src/pages/App.js
index 87c139ec..26ded58c 100644
--- a/src/pages/App.js
+++ b/src/pages/App.js
@@ -7,7 +7,7 @@ import {openSimulationSucceeded} from "../actions/simulations";
import {resetCurrentDatacenter} from "../actions/topology/building";
import LoadingScreen from "../components/map/LoadingScreen";
import AppNavbar from "../components/navigation/AppNavbar";
-import Timeline from "../components/timeline/Timeline";
+import SimulationSidebarComponent from "../components/sidebars/simulation/SimulationSidebarComponent";
import MapStage from "../containers/map/MapStage";
import DeleteMachineModal from "../containers/modals/DeleteMachineModal";
import DeleteRackModal from "../containers/modals/DeleteRackModal";
@@ -15,6 +15,7 @@ import DeleteRoomModal from "../containers/modals/DeleteRoomModal";
import EditRackNameModal from "../containers/modals/EditRackNameModal";
import EditRoomNameModal from "../containers/modals/EditRoomNameModal";
import TopologySidebar from "../containers/sidebars/topology/TopologySidebar";
+import TimelineContainer from "../containers/timeline/TimelineContainer";
import KeymapConfiguration from "../shortcuts/keymap";
const shortcutManager = new ShortcutManager(KeymapConfiguration);
@@ -56,7 +57,11 @@ class AppComponent extends React.Component {
<MapStage/>
<TopologySidebar/>
{this.props.inSimulation ?
- <Timeline/> :
+ <TimelineContainer/> :
+ undefined
+ }
+ {this.props.inSimulation ?
+ <SimulationSidebarComponent/> :
undefined
}
</div>
diff --git a/src/reducers/construction-mode.js b/src/reducers/construction-mode.js
index 3e0b7542..e97c817e 100644
--- a/src/reducers/construction-mode.js
+++ b/src/reducers/construction-mode.js
@@ -1,4 +1,5 @@
import {combineReducers} from "redux";
+import {OPEN_EXPERIMENT_SUCCEEDED} from "../actions/experiments";
import {
CANCEL_NEW_ROOM_CONSTRUCTION_SUCCEEDED,
FINISH_NEW_ROOM_CONSTRUCTION,
@@ -12,6 +13,7 @@ export function currentRoomInConstruction(state = -1, action) {
return action.roomId;
case CANCEL_NEW_ROOM_CONSTRUCTION_SUCCEEDED:
case FINISH_NEW_ROOM_CONSTRUCTION:
+ case OPEN_EXPERIMENT_SUCCEEDED:
return -1;
default:
return state;
@@ -23,6 +25,7 @@ export function inRackConstructionMode(state = false, action) {
case START_RACK_CONSTRUCTION:
return true;
case STOP_RACK_CONSTRUCTION:
+ case OPEN_EXPERIMENT_SUCCEEDED:
return false;
default:
return state;
diff --git a/src/reducers/interaction-level.js b/src/reducers/interaction-level.js
index a3f3de7f..282e5096 100644
--- a/src/reducers/interaction-level.js
+++ b/src/reducers/interaction-level.js
@@ -1,12 +1,19 @@
+import {OPEN_EXPERIMENT_SUCCEEDED} from "../actions/experiments";
import {
GO_DOWN_ONE_INTERACTION_LEVEL,
GO_FROM_BUILDING_TO_ROOM,
GO_FROM_RACK_TO_MACHINE,
GO_FROM_ROOM_TO_RACK
} from "../actions/interaction-level";
+import {OPEN_SIMULATION_SUCCEEDED} from "../actions/simulations";
export function interactionLevel(state = {mode: "BUILDING"}, action) {
switch (action.type) {
+ case OPEN_EXPERIMENT_SUCCEEDED:
+ case OPEN_SIMULATION_SUCCEEDED:
+ return {
+ mode: "BUILDING"
+ };
case GO_FROM_BUILDING_TO_ROOM:
return {
mode: "ROOM",
diff --git a/src/reducers/modals.js b/src/reducers/modals.js
index 9f73c6ec..3e9f0327 100644
--- a/src/reducers/modals.js
+++ b/src/reducers/modals.js
@@ -1,4 +1,5 @@
import {combineReducers} from "redux";
+import {OPEN_EXPERIMENT_SUCCEEDED} from "../actions/experiments";
import {CLOSE_NEW_EXPERIMENT_MODAL, OPEN_NEW_EXPERIMENT_MODAL} from "../actions/modals/experiments";
import {CLOSE_DELETE_PROFILE_MODAL, OPEN_DELETE_PROFILE_MODAL} from "../actions/modals/profile";
import {CLOSE_NEW_SIMULATION_MODAL, OPEN_NEW_SIMULATION_MODAL} from "../actions/modals/simulations";
@@ -21,6 +22,7 @@ function modal(openAction, closeAction) {
case openAction:
return true;
case closeAction:
+ case OPEN_EXPERIMENT_SUCCEEDED:
return false;
default:
return state;
diff --git a/src/reducers/simulation-mode.js b/src/reducers/simulation-mode.js
index 60084824..b13ecbcc 100644
--- a/src/reducers/simulation-mode.js
+++ b/src/reducers/simulation-mode.js
@@ -2,11 +2,14 @@ import {OPEN_EXPERIMENT_SUCCEEDED} from "../actions/experiments";
import {CHANGE_LOAD_METRIC} from "../actions/simulation/load-metric";
import {SET_PLAYING} from "../actions/simulation/playback";
import {GO_TO_TICK, SET_LAST_SIMULATED_TICK} from "../actions/simulation/tick";
+import {OPEN_SIMULATION_SUCCEEDED} from "../actions/simulations";
export function currentExperimentId(state = -1, action) {
switch (action.type) {
case OPEN_EXPERIMENT_SUCCEEDED:
return action.experimentId;
+ case OPEN_SIMULATION_SUCCEEDED:
+ return -1;
default:
return state;
}
@@ -16,6 +19,8 @@ export function currentTick(state = 0, action) {
switch (action.type) {
case GO_TO_TICK:
return action.tick;
+ case OPEN_EXPERIMENT_SUCCEEDED:
+ return 0;
default:
return state;
}
@@ -34,6 +39,8 @@ export function isPlaying(state = false, action) {
switch (action.type) {
case SET_PLAYING:
return action.playing;
+ case OPEN_EXPERIMENT_SUCCEEDED:
+ return false;
default:
return state;
}
@@ -43,6 +50,8 @@ export function lastSimulatedTick(state = -1, action) {
switch (action.type) {
case SET_LAST_SIMULATED_TICK:
return action.tick;
+ case OPEN_EXPERIMENT_SUCCEEDED:
+ return -1;
default:
return state;
}
diff --git a/src/sagas/experiments.js b/src/sagas/experiments.js
index cf92e97f..29f9a211 100644
--- a/src/sagas/experiments.js
+++ b/src/sagas/experiments.js
@@ -1,15 +1,23 @@
import {call, put, select} from "redux-saga/effects";
import {addPropToStoreObject, addToStore} from "../actions/objects";
import {deleteExperiment, getExperiment} from "../api/routes/experiments";
-import {addExperiment, getExperimentsOfSimulation} from "../api/routes/simulations";
+import {getTasksOfJob} from "../api/routes/jobs";
+import {addExperiment, getExperimentsOfSimulation, getSimulation} from "../api/routes/simulations";
+import {getJobsOfTrace} from "../api/routes/traces";
import {fetchAndStoreAllSchedulers, fetchAndStoreAllTraces, fetchAndStorePathsOfSimulation} from "./objects";
import {fetchAllDatacentersOfExperiment} from "./topology";
export function* onOpenExperimentSucceeded(action) {
try {
+ const simulation = yield call(getSimulation, action.simulationId);
+ yield put(addToStore("simulation", simulation));
+
const experiment = yield call(getExperiment, action.experimentId);
yield put(addToStore("experiment", experiment));
+ yield fetchExperimentSpecifications();
+ yield fetchWorkloadOfTrace(experiment.traceId);
+
yield fetchAllDatacentersOfExperiment(experiment);
} catch (error) {
console.error(error);
@@ -43,6 +51,24 @@ function* fetchExperimentSpecifications() {
}
}
+function* fetchWorkloadOfTrace(traceId) {
+ try {
+ const jobs = yield call(getJobsOfTrace, traceId);
+ for (let i in jobs) {
+ const job = jobs[i];
+ const tasks = yield call(getTasksOfJob, job.id);
+ job.taskIds = tasks.map(task => task.id);
+ for (let j in tasks) {
+ yield put(addToStore("task", tasks[j]));
+ }
+ yield put(addToStore("job", job));
+ }
+ yield put(addPropToStoreObject("trace", traceId, {jobIds: jobs.map(job => job.id)}))
+ } catch (error) {
+ console.error(error);
+ }
+}
+
export function* onAddExperiment(action) {
try {
const currentSimulationId = yield select(state => state.currentSimulationId);