Skip to content
This repository has been archived by the owner on Jul 10, 2024. It is now read-only.

Commit

Permalink
SUBMARINE-590. [WEB] Update chart/param/metric UI
Browse files Browse the repository at this point in the history
### What is this PR for?
- Improve chart/param/metric UI
- Fix the database connection error due to the update in SUBMARINE-575
- Read the data from the `metric` table, and draw charts in workbench

Following commands could reproduce the experiment
```bash
curl -X POST -H "Content-Type: application/json" -d '
{
  "meta": {
    "name": "tf-mnist2",
    "namespace": "submarine",
    "framework": "TensorFlow",
    "cmd": "python3 /var/example/tracking.py",
    "envVars": {
      "ENV_1": "ENV1"
    }
  },
  "environment": {
    "image": "pingsutw/tracking-example:0.5.0.dev"
  },
  "spec": {
    "Ps": {
      "replicas": 1,
      "resources": "cpu=1,memory=1024M"
    },
    "Worker": {
      "replicas": 1,
      "resources": "cpu=1,memory=1024M"
    }
  }
}
' http://127.0.0.1:8080/api/v1/experiment

```

### What type of PR is it?
[Improvement]

### Todos
* [ ] - Task

### What is the Jira issue?
https://issues.apache.org/jira/browse/SUBMARINE-590

### How should this be tested?
https://travis-ci.org/github/pingsutw/hadoop-submarine/builds/714396434

### Screenshots (if appropriate)
![Screenshot from 2020-08-03 12-42-34](https://user-images.githubusercontent.com/37936015/89163413-1f071000-d5a8-11ea-9b44-c7646ccb2868.png)

![Screenshot from 2020-08-03 12-42-35](https://user-images.githubusercontent.com/37936015/89163445-29290e80-d5a8-11ea-943e-e59eb3c753f4.png)

![Screenshot from 2020-08-03 12-42-38](https://user-images.githubusercontent.com/37936015/89163458-2d552c00-d5a8-11ea-9c3a-c250f06f32ef.png)

![Screenshot from 2020-08-03 12-42-37](https://user-images.githubusercontent.com/37936015/89163454-2af2d200-d5a8-11ea-9274-52fc5ccdb7a5.png)

### Questions:
* Does the licenses files need update? No
* Is there breaking changes for older versions? No
* Does this needs documentation? No

Author: Kevin Su <[email protected]>
Author: HUAN-PING SU <[email protected]>

Closes #369 from pingsutw/SUBMARINE-590 and squashes the following commits:

e2020bf [HUAN-PING SU] Update submarine-server/server-core/src/main/java/org/apache/submarine/server/experiment/ExperimentManager.java
d8a9a58 [HUAN-PING SU] Update submarine-server/server-core/src/main/java/org/apache/submarine/server/experiment/ExperimentManager.java
8449fe5 [Kevin Su] Remove unused import
c76615e [Kevin Su] Update github action
a211cc0 [Kevin Su] Update github action
fbcab9e [Kevin Su] Update github action
866f383 [Kevin Su] Update experimentManager
4f19fc6 [Kevin Su] Update proxy.conf.js
9ab5856 [Kevin Su] Update ExperimentManager
b1f6e08 [Kevin Su] update python github action
983608a [Kevin Su] update python github action
48074bb [Kevin Su] update python github action
bf1c637 [Kevin Su] update python github action
ad1229a [Kevin Su] update chart
b0312d1 [Kevin Su] update chart
3404264 [Kevin Su] update chart
0469b06 [Kevin Su] update chart
97ed6e0 [Kevin Su] update python github action
a966310 [Kevin Su] Update chart
a2d5d4f [Kevin Su] Add angular cdk
0a4b34d [Kevin Su] Update workbench
9a50983 [Kevin Su] Fix show param in workbench
  • Loading branch information
pingsutw authored and xunliu committed Aug 12, 2020
1 parent 517083e commit cc9dde5
Show file tree
Hide file tree
Showing 23 changed files with 172 additions and 192 deletions.
7 changes: 3 additions & 4 deletions .github/workflows/python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ jobs:
- name: Install dependencies
run: |
pip install --upgrade pip
pip install ./submarine-sdk/pysubmarine/.
pip install -q tensorflow==${{ matrix.tf-version }}
pip install --no-cache-dir tensorflow==${{ matrix.tf-version }}
pip install --no-cache-dir torch==1.5.0
pip install --no-cache-dir ./submarine-sdk/pysubmarine/.
pip install -r ./submarine-sdk/pysubmarine/github-actions/test-requirements.txt
pip install -r ./submarine-sdk/pysubmarine/github-actions/lint-requirements.txt
- name: Check python sdk code style
Expand All @@ -47,5 +48,3 @@ jobs:
- name: Test with pytest
run: |
pytest --cov=submarine -vs
2 changes: 1 addition & 1 deletion submarine-sdk/pysubmarine/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
'certifi >= 14.05.14',
'python-dateutil >= 2.5.3',
'pyarrow==0.17.0',
'torch>=1.4.0',
'torch>=1.5.0',
],
classifiers=[
'Intended Audience :: Developers',
Expand Down
11 changes: 6 additions & 5 deletions submarine-sdk/pysubmarine/submarine/tracking/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,11 @@

_TF_CONFIG = "TF_CONFIG"
_CLUSTER_SPEC = "CLUSTER_SPEC"
_TASK_INDEX = "TASK_INDEX"
_JOB_NAME = "JOB_NAME"
_TYPE = "type"
_TASK = "task"
_INDEX = "index"
_RANK = "RANK"
_TASK = "TASK"

# Extra environment variables which take precedence for setting the basic/bearer
# auth on http requests.
Expand Down Expand Up @@ -98,14 +99,14 @@ def get_worker_index():
if env.get_env(_TF_CONFIG) is not None:
tf_config = json.loads(os.environ.get(_TF_CONFIG))
task_config = tf_config.get(_TASK)
task_type = task_config.get(_JOB_NAME)
task_index = task_config.get(_TASK_INDEX)
task_type = task_config.get(_TYPE)
task_index = task_config.get(_INDEX)
worker_index = task_type + '-' + str(task_index)
elif env.get_env(_CLUSTER_SPEC) is not None:
cluster_spec = json.loads(os.environ.get(_CLUSTER_SPEC))
task_config = cluster_spec.get(_TASK)
task_type = task_config.get(_JOB_NAME)
task_index = task_config.get(_TASK_INDEX)
task_index = task_config.get(_INDEX)
worker_index = task_type + '-' + str(task_index)
# Get PyTorch worker index
elif env.get_env(_RANK) is not None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

import javax.ws.rs.core.Response.Status;

import org.apache.submarine.commons.utils.SubmarineConfiguration;
import org.apache.submarine.commons.utils.exception.SubmarineRuntimeException;
import org.apache.submarine.server.SubmarineServer;
import org.apache.submarine.server.SubmitterManager;
Expand All @@ -36,6 +37,7 @@
import org.apache.submarine.server.api.Submitter;
import org.apache.submarine.server.api.experiment.ExperimentLog;
import org.apache.submarine.server.api.spec.ExperimentSpec;
import org.apache.submarine.server.rest.RestConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -85,13 +87,33 @@ private ExperimentManager(Submitter submitter) {
*/
public Experiment createExperiment(ExperimentSpec spec) throws SubmarineRuntimeException {
checkSpec(spec);

// Submarine sdk will get experimentID and JDBC URL from environment variables in each worker,
// and then log experiment metrics and parameters to submarine server
ExperimentId id = generateExperimentId();
String url = getSQLAlchemyURL();
spec.getMeta().getEnvVars().put(RestConstants.JOB_ID, id.toString());
spec.getMeta().getEnvVars().put(RestConstants.SUBMARINE_TRACKING_URI, url);

Experiment experiment = submitter.createExperiment(spec);
experiment.setExperimentId(generateExperimentId());
experiment.setExperimentId(id);

spec.getMeta().getEnvVars().remove(RestConstants.JOB_ID);
spec.getMeta().getEnvVars().remove(RestConstants.SUBMARINE_TRACKING_URI);
experiment.setSpec(spec);
cachedExperimentMap.putIfAbsent(experiment.getExperimentId().toString(), experiment);
return experiment;
}

private String getSQLAlchemyURL() {
SubmarineConfiguration conf = SubmarineConfiguration.getInstance();
String jdbcUrl = conf.getJdbcUrl();
jdbcUrl = jdbcUrl.substring(jdbcUrl.indexOf("//") + 2, jdbcUrl.indexOf("?"));
String jdbcUserName = conf.getJdbcUserName();
String jdbcPassword = conf.getJdbcPassword();
return "mysql+pymysql://" + jdbcUserName + ":" + jdbcPassword + "@" + jdbcUrl;
}

private ExperimentId generateExperimentId() {
return ExperimentId.newInstance(SubmarineServer.getServerTimeStamp(),
experimentCounter.incrementAndGet());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,32 @@

public class RestConstants {
public static final String V1 = "v1";

public static final String EXPERIMENT = "experiment";

public static final String ID = "id";

public static final String JOB_ID = "JOB_ID";

public static final String SUBMARINE_TRACKING_URI = "SUBMARINE_TRACKING_URI";

public static final String PING = "ping";

public static final String MEDIA_TYPE_YAML = "application/yaml";

public static final String CHARSET_UTF8 = "charset=utf-8";

public static final String METASTORE = "metastore";

public static final String CLUSTER = "cluster";

public static final String ADDRESS = "address";

public static final String NODES = "nodes";

public static final String NODE = "node";

public static final String LOGS = "logs";

/**
* Environment
*/
Expand Down
15 changes: 10 additions & 5 deletions submarine-workbench/workbench-web-ng/angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@
"input": "./node_modules/@ant-design/icons-angular/src/inline-svg/",
"output": "/assets/"
},
{ "glob": "**/*",
"input": "./node_modules/ngx-monaco-editor/assets/monaco",
"output": "/assets/monaco/" }
{
"glob": "**/*",
"input": "./node_modules/ngx-monaco-editor/assets/monaco",
"output": "/assets/monaco/"
}
],
"styles": [
"src/theme.less",
Expand Down Expand Up @@ -136,5 +138,8 @@
}
}
},
"defaultProject": "workbench-web-ng"
}
"defaultProject": "workbench-web-ng",
"cli": {
"analytics": false
}
}
4 changes: 2 additions & 2 deletions submarine-workbench/workbench-web-ng/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@
"@angular/animations": "~8.2.9",
"@angular/common": "~8.2.9",
"@angular/compiler": "~8.2.9",
"@angular/core": "~8.2.9",
"@angular/core": "^8.2.14",
"@angular/forms": "~8.2.9",
"@angular/platform-browser": "~8.2.9",
"@angular/platform-browser-dynamic": "~8.2.9",
"@angular/router": "~8.2.9",
"@swimlane/ngx-charts": "^13.0.1",
"date-fns": "^2.6.0",
"lint-staged": "^10.2.2",
"lodash": "^4.17.15",
"lodash": "^4.17.19",
"md5": "^2.2.1",
"ng-zorro-antd": "8.1.2",
"ngx-monaco-editor": "^8.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,26 @@
~ under the License.
-->

<div id="chartsDiv">
<ngx-charts-line-chart
[view]="view"
[scheme]="colorScheme"
[legend]="legend"
[showXAxisLabel]="showXAxisLabel"
[showYAxisLabel]="showYAxisLabel"
[xAxis]="xAxis"
[yAxis]="yAxis"
[xAxisLabel]="xAxisLabel"
[yAxisLabel]="yAxisLabel"
[timeline]="timeline"
[results]="data"
(select)="onSelect($event)"
(activate)="onActivate($event)"
(deactivate)="onDeactivate($event)"
[legendTitle]="title"
></ngx-charts-line-chart>
<div id="chartsTable">
<div *ngFor="let yAxisLabel of yAxisLabels; let index = index">
<ngx-charts-line-chart
[view]="view"
[scheme]="colorScheme[index]"
[legend]="legend"
[showXAxisLabel]="showXAxisLabel"
[showYAxisLabel]="showYAxisLabel"
[xAxis]="xAxis"
[yAxis]="yAxis"
[xAxisLabel]="xAxisLabel"
[yAxisLabel]="yAxisLabel"
[timeline]="timeline"
[results]="podMetrics[yAxisLabel]"
(select)="onSelect($event)"
(activate)="onActivate($event)"
(deactivate)="onDeactivate($event)"
[legendTitle]="title"
>
{{ yAxisLabel }}
</ngx-charts-line-chart>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
* under the License.
*/

#chartsDiv {
background-color: white;
height: 500px;
}
#chartsTable {
background-color: white;
height: 90vh;
overflow: auto;
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,37 +17,32 @@
* under the License.
*/

import { Component, OnInit } from '@angular/core';
import { test_data } from './data';
import { Component, Input, OnInit, SimpleChanges } from '@angular/core';

@Component({
selector: 'submarine-charts',
templateUrl: './charts.component.html',
styleUrls: ['./charts.component.scss']
})
export class ChartsComponent implements OnInit {
title = 'Metrics';
@Input() workerIndex;
@Input() metricData;

data: any[];
view: any[] = [800, 500];
legend: boolean = true;
title = 'Metrics';
podMetrics = {};
view: any[] = [1000, 300];
legend: boolean = false;
showLabels: boolean = true;
animations: boolean = true;
xAxis: boolean = true;
yAxis: boolean = true;
showYAxisLabel: boolean = true;
showXAxisLabel: boolean = true;
xAxisLabel: string = 'Epoch';
yAxisLabel: string = 'Percent';
timeline: boolean = true;

colorScheme = {
domain: ['#5AA454', '#E44D25', '#CFC0BB', '#7aa3e5']
};

constructor() {
this.data = Object.assign([], test_data);
}
xAxisLabel: string = 'Time (s)';
yAxisLabels = [];
timeline: boolean = false;
colorScheme = ['cool', 'fire', 'flame', 'air', 'forest', 'neons', 'ocean'];
constructor() {}

onSelect(data): void {
console.log('Item clicked', JSON.parse(JSON.stringify(data)));
Expand All @@ -62,4 +57,40 @@ export class ChartsComponent implements OnInit {
}

ngOnInit() {}

ngOnChanges(chg: SimpleChanges) {
this.podMetrics = {};
this.yAxisLabels = [];
this.fetchMetric();
}
fetchMetric() {
if (this.metricData === undefined) {
return;
}
let key = '';
let metrics = [];
this.metricData.forEach((data) => {
if (data.workerIndex === undefined) {
return;
}
if (this.workerIndex.indexOf(data.workerIndex) >= 0) {
if (data.key !== key && metrics.length > 0) {
this.yAxisLabels.push(key);
this.podMetrics[key] = [];
this.podMetrics[key].push({ name: key, series: metrics });
metrics = [];
}
key = data.key;
const d = new Date(0);
d.setUTCMilliseconds(data.timestamp);
const metric = { name: d, value: data.value };
metrics.push(metric);
}
});
if (metrics.length > 0) {
this.yAxisLabels.push(key);
this.podMetrics[key] = [];
this.podMetrics[key].push({ name: key, series: metrics });
}
}
}
Loading

0 comments on commit cc9dde5

Please sign in to comment.