Committed by
Gerrit Code Review
Adding test apps as submodule to apps
Moving election and intent-perf there Change-Id: Ia71e98438b33d3a1c5c12b08ae98c32930c4bd81
Showing
29 changed files
with
1999 additions
and
0 deletions
... | @@ -43,6 +43,7 @@ | ... | @@ -43,6 +43,7 @@ |
43 | <module>routing</module> | 43 | <module>routing</module> |
44 | <module>routing-api</module> | 44 | <module>routing-api</module> |
45 | <module>bgprouter</module> | 45 | <module>bgprouter</module> |
46 | + <module>test</module> | ||
46 | </modules> | 47 | </modules> |
47 | 48 | ||
48 | <properties> | 49 | <properties> | ... | ... |
apps/test/election/pom.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<!-- | ||
3 | + ~ Copyright 2014 Open Networking Laboratory | ||
4 | + ~ | ||
5 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + ~ you may not use this file except in compliance with the License. | ||
7 | + ~ You may obtain a copy of the License at | ||
8 | + ~ | ||
9 | + ~ http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + ~ | ||
11 | + ~ Unless required by applicable law or agreed to in writing, software | ||
12 | + ~ distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + ~ See the License for the specific language governing permissions and | ||
15 | + ~ limitations under the License. | ||
16 | + --> | ||
17 | + | ||
18 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
19 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
20 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
21 | + <modelVersion>4.0.0</modelVersion> | ||
22 | + | ||
23 | + <parent> | ||
24 | + <groupId>org.onosproject</groupId> | ||
25 | + <artifactId>onos-app-samples</artifactId> | ||
26 | + <version>1.2.0-SNAPSHOT</version> | ||
27 | + <relativePath>../pom.xml</relativePath> | ||
28 | + </parent> | ||
29 | + | ||
30 | + <artifactId>onos-app-election</artifactId> | ||
31 | + <packaging>bundle</packaging> | ||
32 | + | ||
33 | + <description>ONOS app leadership election test</description> | ||
34 | + | ||
35 | + <dependencies> | ||
36 | + | ||
37 | + <dependency> | ||
38 | + <groupId>org.onosproject</groupId> | ||
39 | + <artifactId>onos-api</artifactId> | ||
40 | + <version>${project.version}</version> | ||
41 | + <scope>test</scope> | ||
42 | + <classifier>tests</classifier> | ||
43 | + </dependency> | ||
44 | + | ||
45 | + <dependency> | ||
46 | + <groupId>org.onosproject</groupId> | ||
47 | + <artifactId>onos-cli</artifactId> | ||
48 | + <version>${project.version}</version> | ||
49 | + </dependency> | ||
50 | + | ||
51 | + <dependency> | ||
52 | + <groupId>org.osgi</groupId> | ||
53 | + <artifactId>org.osgi.core</artifactId> | ||
54 | + </dependency> | ||
55 | + <dependency> | ||
56 | + <groupId>org.apache.karaf.shell</groupId> | ||
57 | + <artifactId>org.apache.karaf.shell.console</artifactId> | ||
58 | + </dependency> | ||
59 | + | ||
60 | + </dependencies> | ||
61 | + | ||
62 | +</project> |
1 | +/* | ||
2 | + * Copyright 2014 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onosproject.election; | ||
17 | + | ||
18 | +import static org.slf4j.LoggerFactory.getLogger; | ||
19 | + | ||
20 | +import org.apache.felix.scr.annotations.Activate; | ||
21 | +import org.apache.felix.scr.annotations.Component; | ||
22 | +import org.apache.felix.scr.annotations.Deactivate; | ||
23 | +import org.apache.felix.scr.annotations.Reference; | ||
24 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
25 | +import org.onosproject.cluster.ClusterService; | ||
26 | +import org.onosproject.core.CoreService; | ||
27 | +import org.onosproject.cluster.ControllerNode; | ||
28 | +import org.onosproject.cluster.LeadershipEvent; | ||
29 | +import org.onosproject.cluster.LeadershipEventListener; | ||
30 | +import org.onosproject.cluster.LeadershipService; | ||
31 | +import org.onosproject.core.ApplicationId; | ||
32 | + | ||
33 | +import org.slf4j.Logger; | ||
34 | + | ||
35 | + | ||
36 | +/** | ||
37 | + * Simple application to test leadership election. | ||
38 | + */ | ||
39 | +@Component(immediate = true) | ||
40 | +public class ElectionTest { | ||
41 | + | ||
42 | + private final Logger log = getLogger(getClass()); | ||
43 | + | ||
44 | + private static final String ELECTION_APP = "org.onosproject.election"; | ||
45 | + private ApplicationId appId; | ||
46 | + | ||
47 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
48 | + protected ClusterService clusterService; | ||
49 | + | ||
50 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
51 | + protected CoreService coreService; | ||
52 | + | ||
53 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
54 | + protected LeadershipService leadershipService; | ||
55 | + | ||
56 | + private LeadershipEventListener leadershipEventListener = | ||
57 | + new InnerLeadershipEventListener(); | ||
58 | + | ||
59 | + private ControllerNode localControllerNode; | ||
60 | + | ||
61 | + | ||
62 | + @Activate | ||
63 | + protected void activate() { | ||
64 | + log.info("Election-test app started"); | ||
65 | + | ||
66 | + appId = coreService.registerApplication(ELECTION_APP); | ||
67 | + | ||
68 | + localControllerNode = clusterService.getLocalNode(); | ||
69 | + | ||
70 | + leadershipService.addListener(leadershipEventListener); | ||
71 | + leadershipService.runForLeadership(appId.name()); | ||
72 | + } | ||
73 | + | ||
74 | + @Deactivate | ||
75 | + protected void deactivate() { | ||
76 | + | ||
77 | + leadershipService.withdraw(appId.name()); | ||
78 | + leadershipService.removeListener(leadershipEventListener); | ||
79 | + | ||
80 | + log.info("Election-test app Stopped"); | ||
81 | + } | ||
82 | + | ||
83 | + /** | ||
84 | + * A listener for Leadership Events. | ||
85 | + */ | ||
86 | + private class InnerLeadershipEventListener | ||
87 | + implements LeadershipEventListener { | ||
88 | + | ||
89 | + @Override | ||
90 | + public void event(LeadershipEvent event) { | ||
91 | + | ||
92 | + | ||
93 | + if (!event.subject().topic().equals(appId.name())) { | ||
94 | + return; // Not our topic: ignore | ||
95 | + } | ||
96 | + | ||
97 | + //only log what pertains to us | ||
98 | + log.debug("Leadership Event: time = {} type = {} event = {}", | ||
99 | + event.time(), event.type(), event); | ||
100 | + | ||
101 | + if (!event.subject().leader().equals( | ||
102 | + localControllerNode.id())) { | ||
103 | + return; // The event is not about this instance: ignore | ||
104 | + } | ||
105 | + | ||
106 | + switch (event.type()) { | ||
107 | + case LEADER_ELECTED: | ||
108 | + log.info("Election-test app leader elected"); | ||
109 | + break; | ||
110 | + case LEADER_BOOTED: | ||
111 | + log.info("Election-test app lost election"); | ||
112 | + break; | ||
113 | + case LEADER_REELECTED: | ||
114 | + log.debug("Election-test app was re-elected"); | ||
115 | + break; | ||
116 | + default: | ||
117 | + break; | ||
118 | + } | ||
119 | + } | ||
120 | + } | ||
121 | + | ||
122 | +} |
apps/test/election/src/main/java/org/onosproject/election/cli/ElectionTestLeaderCommand.java
0 → 100644
1 | +/* | ||
2 | + * Copyright 2014 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onosproject.election.cli; | ||
17 | + | ||
18 | +import org.onosproject.cluster.NodeId; | ||
19 | +import org.apache.karaf.shell.commands.Command; | ||
20 | +import org.onosproject.cli.AbstractShellCommand; | ||
21 | +import org.onosproject.cluster.LeadershipService; | ||
22 | + | ||
23 | +/** | ||
24 | + * CLI command to get the current leader for the Election test application. | ||
25 | + */ | ||
26 | +@Command(scope = "onos", name = "election-test-leader", | ||
27 | + description = "Get the current leader for the Election test application") | ||
28 | +public class ElectionTestLeaderCommand extends AbstractShellCommand { | ||
29 | + | ||
30 | + private NodeId leader; | ||
31 | + private static final String ELECTION_APP = "org.onosproject.election"; | ||
32 | + | ||
33 | + @Override | ||
34 | + protected void execute() { | ||
35 | + LeadershipService service = get(LeadershipService.class); | ||
36 | + | ||
37 | + //print the current leader | ||
38 | + leader = service.getLeader(ELECTION_APP); | ||
39 | + printLeader(leader); | ||
40 | + } | ||
41 | + | ||
42 | + /** | ||
43 | + * Prints the leader. | ||
44 | + * | ||
45 | + * @param leader the leader to print | ||
46 | + */ | ||
47 | + private void printLeader(NodeId leader) { | ||
48 | + if (leader != null) { | ||
49 | + print("The current leader for the Election app is %s.", leader); | ||
50 | + } else { | ||
51 | + print("There is currently no leader elected for the Election app"); | ||
52 | + } | ||
53 | + } | ||
54 | +} |
apps/test/election/src/main/java/org/onosproject/election/cli/ElectionTestRunCommand.java
0 → 100644
1 | +/* | ||
2 | + * Copyright 2014 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onosproject.election.cli; | ||
17 | + | ||
18 | +import org.apache.karaf.shell.commands.Command; | ||
19 | +import org.onosproject.cli.AbstractShellCommand; | ||
20 | +import org.onosproject.cluster.LeadershipService; | ||
21 | + | ||
22 | +/** | ||
23 | + * CLI command to run for leadership of the Election test application. | ||
24 | + */ | ||
25 | +@Command(scope = "onos", name = "election-test-run", | ||
26 | + description = "Run for leader of the Election test application") | ||
27 | +public class ElectionTestRunCommand extends AbstractShellCommand { | ||
28 | + | ||
29 | + private static final String ELECTION_APP = "org.onosproject.election"; | ||
30 | + | ||
31 | + @Override | ||
32 | + protected void execute() { | ||
33 | + LeadershipService service = get(LeadershipService.class); | ||
34 | + | ||
35 | + service.runForLeadership(ELECTION_APP); | ||
36 | + //print the current leader | ||
37 | + print("Entering leadership elections for the Election app."); | ||
38 | + } | ||
39 | +} |
apps/test/election/src/main/java/org/onosproject/election/cli/ElectionTestWithdrawCommand.java
0 → 100644
1 | +/* | ||
2 | + * Copyright 2014 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onosproject.election.cli; | ||
17 | + | ||
18 | +import org.apache.karaf.shell.commands.Command; | ||
19 | +import org.onosproject.cli.AbstractShellCommand; | ||
20 | +import org.onosproject.cluster.LeadershipService; | ||
21 | + | ||
22 | +/** | ||
23 | + * CLI command to withdraw the local node from leadership election for | ||
24 | + * the Election test application. | ||
25 | + */ | ||
26 | +@Command(scope = "onos", name = "election-test-withdraw", | ||
27 | + description = "Withdraw node from leadership election for the Election test application") | ||
28 | +public class ElectionTestWithdrawCommand extends AbstractShellCommand { | ||
29 | + | ||
30 | + private static final String ELECTION_APP = "org.onosproject.election"; | ||
31 | + | ||
32 | + @Override | ||
33 | + protected void execute() { | ||
34 | + LeadershipService service = get(LeadershipService.class); | ||
35 | + | ||
36 | + service.withdraw(ELECTION_APP); | ||
37 | + //print the current leader | ||
38 | + print("Withdrawing from leadership elections for the Election app."); | ||
39 | + } | ||
40 | +} |
1 | +/* | ||
2 | + * Copyright 2014 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +/** | ||
18 | + * Election test command-line handlers. | ||
19 | + */ | ||
20 | +package org.onosproject.election.cli; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +/* | ||
2 | + * Copyright 2014 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +/** | ||
18 | + * Sample application for use in various experiments. | ||
19 | + */ | ||
20 | +package org.onosproject.election; |
1 | +<!-- | ||
2 | + ~ Copyright 2014 Open Networking Laboratory | ||
3 | + ~ | ||
4 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + ~ you may not use this file except in compliance with the License. | ||
6 | + ~ You may obtain a copy of the License at | ||
7 | + ~ | ||
8 | + ~ http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + ~ | ||
10 | + ~ Unless required by applicable law or agreed to in writing, software | ||
11 | + ~ distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + ~ See the License for the specific language governing permissions and | ||
14 | + ~ limitations under the License. | ||
15 | + --> | ||
16 | +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"> | ||
17 | + | ||
18 | + <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0"> | ||
19 | + <command> | ||
20 | + <action class="org.onosproject.election.cli.ElectionTestLeaderCommand"/> | ||
21 | + </command> | ||
22 | + <command> | ||
23 | + <action class="org.onosproject.election.cli.ElectionTestRunCommand"/> | ||
24 | + </command> | ||
25 | + <command> | ||
26 | + <action class="org.onosproject.election.cli.ElectionTestWithdrawCommand"/> | ||
27 | + </command> | ||
28 | + </command-bundle> | ||
29 | + | ||
30 | +</blueprint> |
apps/test/intent-perf/pom.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<!-- | ||
3 | + ~ Copyright 2015 Open Networking Laboratory | ||
4 | + ~ | ||
5 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + ~ you may not use this file except in compliance with the License. | ||
7 | + ~ You may obtain a copy of the License at | ||
8 | + ~ | ||
9 | + ~ http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + ~ | ||
11 | + ~ Unless required by applicable law or agreed to in writing, software | ||
12 | + ~ distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + ~ See the License for the specific language governing permissions and | ||
15 | + ~ limitations under the License. | ||
16 | + --> | ||
17 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
18 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
19 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
20 | + <modelVersion>4.0.0</modelVersion> | ||
21 | + | ||
22 | + <parent> | ||
23 | + <groupId>org.onosproject</groupId> | ||
24 | + <artifactId>onos-app-samples</artifactId> | ||
25 | + <version>1.2.0-SNAPSHOT</version> | ||
26 | + <relativePath>../pom.xml</relativePath> | ||
27 | + </parent> | ||
28 | + | ||
29 | + <artifactId>onos-app-intent-perf</artifactId> | ||
30 | + <packaging>bundle</packaging> | ||
31 | + | ||
32 | + <description>ONOS intent perf app bundle</description> | ||
33 | + | ||
34 | + <dependencies> | ||
35 | + <dependency> | ||
36 | + <groupId>org.apache.karaf.shell</groupId> | ||
37 | + <artifactId>org.apache.karaf.shell.console</artifactId> | ||
38 | + </dependency> | ||
39 | + | ||
40 | + <dependency> | ||
41 | + <groupId>org.onosproject</groupId> | ||
42 | + <artifactId>onos-cli</artifactId> | ||
43 | + <version>${project.version}</version> | ||
44 | + </dependency> | ||
45 | + <dependency> | ||
46 | + <groupId>org.osgi</groupId> | ||
47 | + <artifactId>org.osgi.compendium</artifactId> | ||
48 | + </dependency> | ||
49 | + <!-- Required for javadoc generation --> | ||
50 | + <dependency> | ||
51 | + <groupId>org.osgi</groupId> | ||
52 | + <artifactId>org.osgi.core</artifactId> | ||
53 | + </dependency> | ||
54 | + </dependencies> | ||
55 | + | ||
56 | + <build> | ||
57 | + <plugins> | ||
58 | + <plugin> | ||
59 | + <groupId>org.apache.maven.plugins</groupId> | ||
60 | + <artifactId>maven-assembly-plugin</artifactId> | ||
61 | + <version>2.5.3</version> | ||
62 | + <configuration> | ||
63 | + <descriptor>src/assembly/bin.xml</descriptor> | ||
64 | + </configuration> | ||
65 | + <executions> | ||
66 | + <execution> | ||
67 | + <phase>package</phase> | ||
68 | + <goals> | ||
69 | + <goal>single</goal> | ||
70 | + </goals> | ||
71 | + </execution> | ||
72 | + </executions> | ||
73 | + </plugin> | ||
74 | + </plugins> | ||
75 | + </build> | ||
76 | +</project> |
apps/test/intent-perf/src/assembly/app.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<!-- | ||
3 | + ~ Copyright 2015 Open Networking Laboratory | ||
4 | + ~ | ||
5 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + ~ you may not use this file except in compliance with the License. | ||
7 | + ~ You may obtain a copy of the License at | ||
8 | + ~ | ||
9 | + ~ http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + ~ | ||
11 | + ~ Unless required by applicable law or agreed to in writing, software | ||
12 | + ~ distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + ~ See the License for the specific language governing permissions and | ||
15 | + ~ limitations under the License. | ||
16 | + --> | ||
17 | +<app name="org.onosproject.intentperf" origin="ON.Lab" version="1.2.0" | ||
18 | + features="onos-app-intent-perf"> | ||
19 | + <description>Intent performance application</description> | ||
20 | +</app> | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
apps/test/intent-perf/src/assembly/bin.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<!-- | ||
3 | + ~ Copyright 2015 Open Networking Laboratory | ||
4 | + ~ | ||
5 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + ~ you may not use this file except in compliance with the License. | ||
7 | + ~ You may obtain a copy of the License at | ||
8 | + ~ | ||
9 | + ~ http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + ~ | ||
11 | + ~ Unless required by applicable law or agreed to in writing, software | ||
12 | + ~ distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + ~ See the License for the specific language governing permissions and | ||
15 | + ~ limitations under the License. | ||
16 | + --> | ||
17 | +<assembly | ||
18 | + xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" | ||
19 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
20 | + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd"> | ||
21 | + <formats> | ||
22 | + <format>zip</format> | ||
23 | + </formats> | ||
24 | + <id>onos</id> | ||
25 | + <includeBaseDirectory>false</includeBaseDirectory> | ||
26 | + <files> | ||
27 | + <file> | ||
28 | + <source>src/assembly/app.xml</source> | ||
29 | + <destName>app.xml</destName> | ||
30 | + </file> | ||
31 | + <file> | ||
32 | + <source>target/${project.artifactId}-${project.version}.jar</source> | ||
33 | + <destName>m2/org/onosproject/${project.artifactId}/${project.version}/${project.artifactId}-${project.version}.jar</destName> | ||
34 | + </file> | ||
35 | + </files> | ||
36 | +</assembly> | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onosproject.intentperf; | ||
17 | + | ||
18 | +import com.google.common.collect.ImmutableList; | ||
19 | +import org.apache.felix.scr.annotations.Activate; | ||
20 | +import org.apache.felix.scr.annotations.Component; | ||
21 | +import org.apache.felix.scr.annotations.Deactivate; | ||
22 | +import org.apache.felix.scr.annotations.Reference; | ||
23 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
24 | +import org.apache.felix.scr.annotations.Service; | ||
25 | +import org.onosproject.cluster.ClusterService; | ||
26 | +import org.onosproject.cluster.ControllerNode; | ||
27 | +import org.onosproject.cluster.NodeId; | ||
28 | +import org.onosproject.store.cluster.messaging.ClusterCommunicationService; | ||
29 | +import org.onosproject.store.cluster.messaging.ClusterMessage; | ||
30 | +import org.onosproject.store.cluster.messaging.ClusterMessageHandler; | ||
31 | +import org.onosproject.store.cluster.messaging.MessageSubject; | ||
32 | +import org.slf4j.Logger; | ||
33 | + | ||
34 | +import java.util.ArrayList; | ||
35 | +import java.util.Arrays; | ||
36 | +import java.util.HashMap; | ||
37 | +import java.util.LinkedList; | ||
38 | +import java.util.List; | ||
39 | +import java.util.Map; | ||
40 | +import java.util.concurrent.ExecutorService; | ||
41 | +import java.util.concurrent.Executors; | ||
42 | + | ||
43 | +import static org.onlab.util.Tools.groupedThreads; | ||
44 | +import static org.slf4j.LoggerFactory.getLogger; | ||
45 | + | ||
46 | +/** | ||
47 | + * Collects and distributes performance samples. | ||
48 | + */ | ||
49 | +@Component(immediate = true) | ||
50 | +@Service(value = IntentPerfCollector.class) | ||
51 | +public class IntentPerfCollector { | ||
52 | + | ||
53 | + private static final long SAMPLE_TIME_WINDOW_MS = 5_000; | ||
54 | + private final Logger log = getLogger(getClass()); | ||
55 | + | ||
56 | + private static final int MAX_SAMPLES = 1_000; | ||
57 | + | ||
58 | + private final List<Sample> samples = new LinkedList<>(); | ||
59 | + | ||
60 | + private static final MessageSubject SAMPLE = new MessageSubject("intent-perf-sample"); | ||
61 | + | ||
62 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
63 | + protected ClusterCommunicationService communicationService; | ||
64 | + | ||
65 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
66 | + protected ClusterService clusterService; | ||
67 | + | ||
68 | + @Reference(cardinality = ReferenceCardinality.OPTIONAL_UNARY) | ||
69 | + protected IntentPerfUi ui; | ||
70 | + | ||
71 | + // Auxiliary structures used to accrue data for normalized time interval | ||
72 | + // across all nodes. | ||
73 | + private long newestTime; | ||
74 | + private Sample overall; | ||
75 | + private Sample current; | ||
76 | + | ||
77 | + private ControllerNode[] nodes; | ||
78 | + private Map<NodeId, Integer> nodeToIndex; | ||
79 | + | ||
80 | + private NodeId nodeId; | ||
81 | + private ExecutorService messageHandlingExecutor; | ||
82 | + | ||
83 | + @Activate | ||
84 | + public void activate() { | ||
85 | + nodeId = clusterService.getLocalNode().id(); | ||
86 | + | ||
87 | + // TODO: replace with shared executor | ||
88 | + messageHandlingExecutor = Executors.newSingleThreadExecutor( | ||
89 | + groupedThreads("onos/perf", "message-handler")); | ||
90 | + | ||
91 | + communicationService.addSubscriber(SAMPLE, new InternalSampleCollector(), | ||
92 | + messageHandlingExecutor); | ||
93 | + | ||
94 | + nodes = clusterService.getNodes().toArray(new ControllerNode[]{}); | ||
95 | + Arrays.sort(nodes, (a, b) -> a.id().toString().compareTo(b.id().toString())); | ||
96 | + | ||
97 | + nodeToIndex = new HashMap<>(); | ||
98 | + for (int i = 0; i < nodes.length; i++) { | ||
99 | + nodeToIndex.put(nodes[i].id(), i); | ||
100 | + } | ||
101 | + | ||
102 | + clearSamples(); | ||
103 | + log.info("Started"); | ||
104 | + } | ||
105 | + | ||
106 | + @Deactivate | ||
107 | + public void deactivate() { | ||
108 | + messageHandlingExecutor.shutdown(); | ||
109 | + communicationService.removeSubscriber(SAMPLE); | ||
110 | + log.info("Stopped"); | ||
111 | + } | ||
112 | + | ||
113 | + /** | ||
114 | + * Clears all previously accumulated data. | ||
115 | + */ | ||
116 | + public void clearSamples() { | ||
117 | + newestTime = 0; | ||
118 | + overall = new Sample(0, nodes.length); | ||
119 | + current = new Sample(0, nodes.length); | ||
120 | + samples.clear(); | ||
121 | + } | ||
122 | + | ||
123 | + | ||
124 | + /** | ||
125 | + * Records a sample point of data about intent operation rate. | ||
126 | + * | ||
127 | + * @param overallRate overall rate | ||
128 | + * @param currentRate current rate | ||
129 | + */ | ||
130 | + public void recordSample(double overallRate, double currentRate) { | ||
131 | + long now = System.currentTimeMillis(); | ||
132 | + addSample(now, nodeId, overallRate, currentRate); | ||
133 | + broadcastSample(now, nodeId, overallRate, currentRate); | ||
134 | + } | ||
135 | + | ||
136 | + /** | ||
137 | + * Returns set of node ids as headers. | ||
138 | + * | ||
139 | + * @return node id headers | ||
140 | + */ | ||
141 | + public List<String> getSampleHeaders() { | ||
142 | + List<String> headers = new ArrayList<>(); | ||
143 | + for (ControllerNode node : nodes) { | ||
144 | + headers.add(node.id().toString()); | ||
145 | + } | ||
146 | + return headers; | ||
147 | + } | ||
148 | + | ||
149 | + /** | ||
150 | + * Returns set of all accumulated samples normalized to the local set of | ||
151 | + * samples. | ||
152 | + * | ||
153 | + * @return accumulated samples | ||
154 | + */ | ||
155 | + public synchronized List<Sample> getSamples() { | ||
156 | + return ImmutableList.copyOf(samples); | ||
157 | + } | ||
158 | + | ||
159 | + /** | ||
160 | + * Returns overall throughput performance for each of the cluster nodes. | ||
161 | + * | ||
162 | + * @return overall intent throughput | ||
163 | + */ | ||
164 | + public synchronized Sample getOverall() { | ||
165 | + return overall; | ||
166 | + } | ||
167 | + | ||
168 | + // Records a new sample to our collection of samples | ||
169 | + private synchronized void addSample(long time, NodeId nodeId, | ||
170 | + double overallRate, double currentRate) { | ||
171 | + Sample fullSample = createCurrentSampleIfNeeded(time); | ||
172 | + setSampleData(current, nodeId, currentRate); | ||
173 | + setSampleData(overall, nodeId, overallRate); | ||
174 | + pruneSamplesIfNeeded(); | ||
175 | + | ||
176 | + if (fullSample != null && ui != null) { | ||
177 | + ui.reportSample(fullSample); | ||
178 | + } | ||
179 | + } | ||
180 | + | ||
181 | + private Sample createCurrentSampleIfNeeded(long time) { | ||
182 | + Sample oldSample = time - newestTime > SAMPLE_TIME_WINDOW_MS || current.isComplete() ? current : null; | ||
183 | + if (oldSample != null) { | ||
184 | + newestTime = time; | ||
185 | + current = new Sample(time, nodes.length); | ||
186 | + if (oldSample.time > 0) { | ||
187 | + samples.add(oldSample); | ||
188 | + } | ||
189 | + } | ||
190 | + return oldSample; | ||
191 | + } | ||
192 | + | ||
193 | + private void setSampleData(Sample sample, NodeId nodeId, double data) { | ||
194 | + Integer index = nodeToIndex.get(nodeId); | ||
195 | + if (index != null) { | ||
196 | + sample.data[index] = data; | ||
197 | + } | ||
198 | + } | ||
199 | + | ||
200 | + private void pruneSamplesIfNeeded() { | ||
201 | + if (samples.size() > MAX_SAMPLES) { | ||
202 | + samples.remove(0); | ||
203 | + } | ||
204 | + } | ||
205 | + | ||
206 | + // Performance data sample. | ||
207 | + static class Sample { | ||
208 | + final long time; | ||
209 | + final double[] data; | ||
210 | + | ||
211 | + public Sample(long time, int nodeCount) { | ||
212 | + this.time = time; | ||
213 | + this.data = new double[nodeCount]; | ||
214 | + Arrays.fill(data, -1); | ||
215 | + } | ||
216 | + | ||
217 | + public boolean isComplete() { | ||
218 | + for (int i = 0; i < data.length; i++) { | ||
219 | + if (data[i] < 0) { | ||
220 | + return false; | ||
221 | + } | ||
222 | + } | ||
223 | + return true; | ||
224 | + } | ||
225 | + } | ||
226 | + | ||
227 | + private void broadcastSample(long time, NodeId nodeId, double overallRate, double currentRate) { | ||
228 | + String data = String.format("%d|%f|%f", time, overallRate, currentRate); | ||
229 | + communicationService.broadcast(new ClusterMessage(nodeId, SAMPLE, data.getBytes())); | ||
230 | + } | ||
231 | + | ||
232 | + private class InternalSampleCollector implements ClusterMessageHandler { | ||
233 | + @Override | ||
234 | + public void handle(ClusterMessage message) { | ||
235 | + String[] fields = new String(message.payload()).split("\\|"); | ||
236 | + log.debug("Received sample from {}: {}", message.sender(), fields); | ||
237 | + addSample(Long.parseLong(fields[0]), message.sender(), | ||
238 | + Double.parseDouble(fields[1]), Double.parseDouble(fields[2])); | ||
239 | + } | ||
240 | + } | ||
241 | +} |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onosproject.intentperf; | ||
17 | + | ||
18 | +import com.google.common.collect.ArrayListMultimap; | ||
19 | +import com.google.common.collect.Lists; | ||
20 | +import com.google.common.collect.Maps; | ||
21 | +import com.google.common.collect.Multimap; | ||
22 | +import com.google.common.collect.Sets; | ||
23 | +import org.apache.commons.lang.math.RandomUtils; | ||
24 | +import org.apache.felix.scr.annotations.Activate; | ||
25 | +import org.apache.felix.scr.annotations.Component; | ||
26 | +import org.apache.felix.scr.annotations.Deactivate; | ||
27 | +import org.apache.felix.scr.annotations.Modified; | ||
28 | +import org.apache.felix.scr.annotations.Property; | ||
29 | +import org.apache.felix.scr.annotations.Reference; | ||
30 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
31 | +import org.apache.felix.scr.annotations.Service; | ||
32 | +import org.onlab.packet.MacAddress; | ||
33 | +import org.onlab.util.Counter; | ||
34 | +import org.onosproject.cfg.ComponentConfigService; | ||
35 | +import org.onosproject.cluster.ClusterService; | ||
36 | +import org.onosproject.cluster.ControllerNode; | ||
37 | +import org.onosproject.cluster.NodeId; | ||
38 | +import org.onosproject.core.ApplicationId; | ||
39 | +import org.onosproject.core.CoreService; | ||
40 | +import org.onosproject.mastership.MastershipService; | ||
41 | +import org.onosproject.net.ConnectPoint; | ||
42 | +import org.onosproject.net.Device; | ||
43 | +import org.onosproject.net.PortNumber; | ||
44 | +import org.onosproject.net.device.DeviceService; | ||
45 | +import org.onosproject.net.flow.DefaultTrafficSelector; | ||
46 | +import org.onosproject.net.flow.DefaultTrafficTreatment; | ||
47 | +import org.onosproject.net.flow.TrafficSelector; | ||
48 | +import org.onosproject.net.flow.TrafficTreatment; | ||
49 | +import org.onosproject.net.intent.Intent; | ||
50 | +import org.onosproject.net.intent.IntentEvent; | ||
51 | +import org.onosproject.net.intent.IntentListener; | ||
52 | +import org.onosproject.net.intent.IntentService; | ||
53 | +import org.onosproject.net.intent.Key; | ||
54 | +import org.onosproject.net.intent.PartitionService; | ||
55 | +import org.onosproject.net.intent.PointToPointIntent; | ||
56 | +import org.onosproject.store.cluster.messaging.ClusterCommunicationService; | ||
57 | +import org.onosproject.store.cluster.messaging.ClusterMessage; | ||
58 | +import org.onosproject.store.cluster.messaging.ClusterMessageHandler; | ||
59 | +import org.onosproject.store.cluster.messaging.MessageSubject; | ||
60 | +import org.osgi.service.component.ComponentContext; | ||
61 | +import org.slf4j.Logger; | ||
62 | + | ||
63 | +import java.util.ArrayList; | ||
64 | +import java.util.Collections; | ||
65 | +import java.util.Dictionary; | ||
66 | +import java.util.List; | ||
67 | +import java.util.Map; | ||
68 | +import java.util.Set; | ||
69 | +import java.util.Timer; | ||
70 | +import java.util.TimerTask; | ||
71 | +import java.util.concurrent.ExecutorService; | ||
72 | +import java.util.concurrent.Executors; | ||
73 | +import java.util.concurrent.TimeUnit; | ||
74 | +import java.util.stream.Collectors; | ||
75 | + | ||
76 | +import static com.google.common.base.Preconditions.checkState; | ||
77 | +import static com.google.common.base.Strings.isNullOrEmpty; | ||
78 | +import static java.lang.String.format; | ||
79 | +import static java.lang.System.currentTimeMillis; | ||
80 | +import static org.apache.felix.scr.annotations.ReferenceCardinality.MANDATORY_UNARY; | ||
81 | +import static org.onlab.util.Tools.*; | ||
82 | +import static org.onosproject.net.intent.IntentEvent.Type.*; | ||
83 | +import static org.slf4j.LoggerFactory.getLogger; | ||
84 | + | ||
85 | +/** | ||
86 | + * Application to test sustained intent throughput. | ||
87 | + */ | ||
88 | +@Component(immediate = true) | ||
89 | +@Service(value = IntentPerfInstaller.class) | ||
90 | +public class IntentPerfInstaller { | ||
91 | + | ||
92 | + private final Logger log = getLogger(getClass()); | ||
93 | + | ||
94 | + private static final int DEFAULT_NUM_WORKERS = 1; | ||
95 | + | ||
96 | + private static final int DEFAULT_NUM_KEYS = 40000; | ||
97 | + private static final int DEFAULT_GOAL_CYCLE_PERIOD = 1000; //ms | ||
98 | + | ||
99 | + private static final int DEFAULT_NUM_NEIGHBORS = 0; | ||
100 | + | ||
101 | + private static final int START_DELAY = 5_000; // ms | ||
102 | + private static final int REPORT_PERIOD = 5_000; //ms | ||
103 | + | ||
104 | + private static final String START = "start"; | ||
105 | + private static final String STOP = "stop"; | ||
106 | + private static final MessageSubject CONTROL = new MessageSubject("intent-perf-ctl"); | ||
107 | + | ||
108 | + //FIXME add path length | ||
109 | + | ||
110 | + @Property(name = "numKeys", intValue = DEFAULT_NUM_KEYS, | ||
111 | + label = "Number of keys (i.e. unique intents) to generate per instance") | ||
112 | + private int numKeys = DEFAULT_NUM_KEYS; | ||
113 | + | ||
114 | + //TODO implement numWorkers property | ||
115 | +// @Property(name = "numThreads", intValue = DEFAULT_NUM_WORKERS, | ||
116 | +// label = "Number of installer threads per instance") | ||
117 | +// private int numWokers = DEFAULT_NUM_WORKERS; | ||
118 | + | ||
119 | + @Property(name = "cyclePeriod", intValue = DEFAULT_GOAL_CYCLE_PERIOD, | ||
120 | + label = "Goal for cycle period (in ms)") | ||
121 | + private int cyclePeriod = DEFAULT_GOAL_CYCLE_PERIOD; | ||
122 | + | ||
123 | + @Property(name = "numNeighbors", intValue = DEFAULT_NUM_NEIGHBORS, | ||
124 | + label = "Number of neighbors to generate intents for") | ||
125 | + private int numNeighbors = DEFAULT_NUM_NEIGHBORS; | ||
126 | + | ||
127 | + @Reference(cardinality = MANDATORY_UNARY) | ||
128 | + protected CoreService coreService; | ||
129 | + | ||
130 | + @Reference(cardinality = MANDATORY_UNARY) | ||
131 | + protected IntentService intentService; | ||
132 | + | ||
133 | + @Reference(cardinality = MANDATORY_UNARY) | ||
134 | + protected ClusterService clusterService; | ||
135 | + | ||
136 | + @Reference(cardinality = MANDATORY_UNARY) | ||
137 | + protected DeviceService deviceService; | ||
138 | + | ||
139 | + @Reference(cardinality = MANDATORY_UNARY) | ||
140 | + protected MastershipService mastershipService; | ||
141 | + | ||
142 | + @Reference(cardinality = MANDATORY_UNARY) | ||
143 | + protected PartitionService partitionService; | ||
144 | + | ||
145 | + @Reference(cardinality = MANDATORY_UNARY) | ||
146 | + protected ComponentConfigService configService; | ||
147 | + | ||
148 | + @Reference(cardinality = MANDATORY_UNARY) | ||
149 | + protected IntentPerfCollector sampleCollector; | ||
150 | + | ||
151 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
152 | + protected ClusterCommunicationService communicationService; | ||
153 | + | ||
154 | + private ExecutorService messageHandlingExecutor; | ||
155 | + | ||
156 | + private ExecutorService workers; | ||
157 | + private ApplicationId appId; | ||
158 | + private Listener listener; | ||
159 | + private boolean stopped; | ||
160 | + | ||
161 | + private Timer reportTimer; | ||
162 | + | ||
163 | + // FIXME this variable isn't shared properly between multiple worker threads | ||
164 | + private int lastKey = 0; | ||
165 | + | ||
166 | + private IntentPerfUi perfUi; | ||
167 | + private NodeId nodeId; | ||
168 | + private TimerTask reporterTask; | ||
169 | + | ||
170 | + @Activate | ||
171 | + public void activate(ComponentContext context) { | ||
172 | + configService.registerProperties(getClass()); | ||
173 | + | ||
174 | + nodeId = clusterService.getLocalNode().id(); | ||
175 | + appId = coreService.registerApplication("org.onosproject.intentperf." + nodeId.toString()); | ||
176 | + | ||
177 | + // TODO: replace with shared timer | ||
178 | + reportTimer = new Timer("onos-intent-perf-reporter"); | ||
179 | + workers = Executors.newFixedThreadPool(DEFAULT_NUM_WORKERS, groupedThreads("onos/intent-perf", "worker-%d")); | ||
180 | + | ||
181 | + // disable flow backups for testing | ||
182 | + configService.setProperty("org.onosproject.store.flow.impl.DistributedFlowRuleStore", | ||
183 | + "backupEnabled", "false"); | ||
184 | + | ||
185 | + // TODO: replace with shared executor | ||
186 | + messageHandlingExecutor = Executors.newSingleThreadExecutor( | ||
187 | + groupedThreads("onos/perf", "command-handler")); | ||
188 | + | ||
189 | + communicationService.addSubscriber(CONTROL, new InternalControl(), | ||
190 | + messageHandlingExecutor); | ||
191 | + | ||
192 | + listener = new Listener(); | ||
193 | + intentService.addListener(listener); | ||
194 | + | ||
195 | + // TODO: investigate why this seems to be necessary for configs to get picked up on initial activation | ||
196 | + modify(context); | ||
197 | + } | ||
198 | + | ||
199 | + @Deactivate | ||
200 | + public void deactivate() { | ||
201 | + stopTestRun(); | ||
202 | + | ||
203 | + configService.unregisterProperties(getClass(), false); | ||
204 | + messageHandlingExecutor.shutdown(); | ||
205 | + communicationService.removeSubscriber(CONTROL); | ||
206 | + | ||
207 | + if (listener != null) { | ||
208 | + reportTimer.cancel(); | ||
209 | + intentService.removeListener(listener); | ||
210 | + listener = null; | ||
211 | + reportTimer = null; | ||
212 | + } | ||
213 | + } | ||
214 | + | ||
215 | + @Modified | ||
216 | + public void modify(ComponentContext context) { | ||
217 | + if (context == null) { | ||
218 | + logConfig("Reconfigured"); | ||
219 | + return; | ||
220 | + } | ||
221 | + | ||
222 | + Dictionary<?, ?> properties = context.getProperties(); | ||
223 | + int newNumKeys, newCyclePeriod, newNumNeighbors; | ||
224 | + try { | ||
225 | + String s = get(properties, "numKeys"); | ||
226 | + newNumKeys = isNullOrEmpty(s) ? numKeys : Integer.parseInt(s.trim()); | ||
227 | + | ||
228 | + s = get(properties, "cyclePeriod"); | ||
229 | + newCyclePeriod = isNullOrEmpty(s) ? cyclePeriod : Integer.parseInt(s.trim()); | ||
230 | + | ||
231 | + s = get(properties, "numNeighbors"); | ||
232 | + newNumNeighbors = isNullOrEmpty(s) ? numNeighbors : Integer.parseInt(s.trim()); | ||
233 | + | ||
234 | + } catch (NumberFormatException | ClassCastException e) { | ||
235 | + log.warn("Malformed configuration detected; using defaults", e); | ||
236 | + newNumKeys = DEFAULT_NUM_KEYS; | ||
237 | + newCyclePeriod = DEFAULT_GOAL_CYCLE_PERIOD; | ||
238 | + newNumNeighbors = DEFAULT_NUM_NEIGHBORS; | ||
239 | + } | ||
240 | + | ||
241 | + if (newNumKeys != numKeys || newCyclePeriod != cyclePeriod || newNumNeighbors != numNeighbors) { | ||
242 | + numKeys = newNumKeys; | ||
243 | + cyclePeriod = newCyclePeriod; | ||
244 | + numNeighbors = newNumNeighbors; | ||
245 | + logConfig("Reconfigured"); | ||
246 | + } | ||
247 | + } | ||
248 | + | ||
249 | + public void start() { | ||
250 | + communicationService.broadcast(new ClusterMessage(nodeId, CONTROL, START.getBytes())); | ||
251 | + startTestRun(); | ||
252 | + } | ||
253 | + | ||
254 | + public void stop() { | ||
255 | + communicationService.broadcast(new ClusterMessage(nodeId, CONTROL, STOP.getBytes())); | ||
256 | + stopTestRun(); | ||
257 | + } | ||
258 | + | ||
259 | + private void logConfig(String prefix) { | ||
260 | + log.info("{} with appId {}; numKeys = {}; cyclePeriod = {} ms; numNeighbors={}", | ||
261 | + prefix, appId.id(), numKeys, cyclePeriod, numNeighbors); | ||
262 | + } | ||
263 | + | ||
264 | + private void startTestRun() { | ||
265 | + sampleCollector.clearSamples(); | ||
266 | + | ||
267 | + // adjust numNeighbors and generate list of neighbors | ||
268 | + numNeighbors = Math.min(clusterService.getNodes().size() - 1, numNeighbors); | ||
269 | + | ||
270 | + // Schedule reporter task on report period boundary | ||
271 | + reporterTask = new ReporterTask(); | ||
272 | + reportTimer.scheduleAtFixedRate(reporterTask, | ||
273 | + REPORT_PERIOD - currentTimeMillis() % REPORT_PERIOD, | ||
274 | + REPORT_PERIOD); | ||
275 | + | ||
276 | + // Submit workers | ||
277 | + stopped = false; | ||
278 | + for (int i = 0; i < DEFAULT_NUM_WORKERS; i++) { | ||
279 | + workers.submit(new Submitter(createIntents(numKeys, /*FIXME*/ 2, lastKey))); | ||
280 | + } | ||
281 | + log.info("Started test run"); | ||
282 | + } | ||
283 | + | ||
284 | + private void stopTestRun() { | ||
285 | + stopped = true; | ||
286 | + if (reporterTask != null) { | ||
287 | + reporterTask.cancel(); | ||
288 | + reporterTask = null; | ||
289 | + } | ||
290 | + | ||
291 | + try { | ||
292 | + workers.awaitTermination(5 * cyclePeriod, TimeUnit.MILLISECONDS); | ||
293 | + } catch (InterruptedException e) { | ||
294 | + log.warn("Failed to stop worker", e); | ||
295 | + } | ||
296 | + log.info("Stopped test run"); | ||
297 | + } | ||
298 | + | ||
299 | + private List<NodeId> getNeighbors() { | ||
300 | + List<NodeId> nodes = clusterService.getNodes().stream() | ||
301 | + .map(ControllerNode::id) | ||
302 | + .collect(Collectors.toCollection(ArrayList::new)); | ||
303 | + // sort neighbors by id | ||
304 | + Collections.sort(nodes, (node1, node2) -> | ||
305 | + node1.toString().compareTo(node2.toString())); | ||
306 | + // rotate the local node to index 0 | ||
307 | + Collections.rotate(nodes, -1 * nodes.indexOf(clusterService.getLocalNode().id())); | ||
308 | + log.debug("neighbors (raw): {}", nodes); //TODO remove | ||
309 | + // generate the sub-list that will contain local node and selected neighbors | ||
310 | + nodes = nodes.subList(0, numNeighbors + 1); | ||
311 | + log.debug("neighbors: {}", nodes); //TODO remove | ||
312 | + return nodes; | ||
313 | + } | ||
314 | + | ||
315 | + private Intent createIntent(Key key, long mac, NodeId node, Multimap<NodeId, Device> devices) { | ||
316 | + // choose a random device for which this node is master | ||
317 | + List<Device> deviceList = devices.get(node).stream().collect(Collectors.toList()); | ||
318 | + Device device = deviceList.get(RandomUtils.nextInt(deviceList.size())); | ||
319 | + | ||
320 | + //FIXME we currently ignore the path length and always use the same device | ||
321 | + TrafficSelector selector = DefaultTrafficSelector.builder() | ||
322 | + .matchEthDst(MacAddress.valueOf(mac)).build(); | ||
323 | + TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment(); | ||
324 | + ConnectPoint ingress = new ConnectPoint(device.id(), PortNumber.portNumber(1)); | ||
325 | + ConnectPoint egress = new ConnectPoint(device.id(), PortNumber.portNumber(2)); | ||
326 | + | ||
327 | + return PointToPointIntent.builder() | ||
328 | + .appId(appId) | ||
329 | + .key(key) | ||
330 | + .selector(selector) | ||
331 | + .treatment(treatment) | ||
332 | + .ingressPoint(ingress) | ||
333 | + .egressPoint(egress) | ||
334 | + .build(); | ||
335 | + } | ||
336 | + | ||
337 | + /** | ||
338 | + * Creates a specified number of intents for testing purposes. | ||
339 | + * | ||
340 | + * @param numberOfKeys number of intents | ||
341 | + * @param pathLength path depth | ||
342 | + * @param firstKey first key to attempt | ||
343 | + * @return set of intents | ||
344 | + */ | ||
345 | + private Set<Intent> createIntents(int numberOfKeys, int pathLength, int firstKey) { | ||
346 | + List<NodeId> neighbors = getNeighbors(); | ||
347 | + | ||
348 | + Multimap<NodeId, Device> devices = ArrayListMultimap.create(); | ||
349 | + deviceService.getAvailableDevices() | ||
350 | + .forEach(device -> devices.put(mastershipService.getMasterFor(device.id()), device)); | ||
351 | + | ||
352 | + // ensure that we have at least one device per neighbor | ||
353 | + neighbors.forEach(node -> checkState(devices.get(node).size() > 0, | ||
354 | + "There are no devices for {}", node)); | ||
355 | + | ||
356 | + // TODO pull this outside so that createIntent can use it | ||
357 | + // prefix based on node id for keys generated on this instance | ||
358 | + long keyPrefix = ((long) clusterService.getLocalNode().ip().getIp4Address().toInt()) << 32; | ||
359 | + | ||
360 | + int maxKeysPerNode = (int) Math.ceil((double) numberOfKeys / neighbors.size()); | ||
361 | + Multimap<NodeId, Intent> intents = ArrayListMultimap.create(); | ||
362 | + | ||
363 | + for (int count = 0, k = firstKey; count < numberOfKeys; k++) { | ||
364 | + Key key = Key.of(keyPrefix + k, appId); | ||
365 | + | ||
366 | + NodeId leader = partitionService.getLeader(key); | ||
367 | + if (!neighbors.contains(leader) || intents.get(leader).size() >= maxKeysPerNode) { | ||
368 | + // Bail if we are not sending to this node or we have enough for this node | ||
369 | + continue; | ||
370 | + } | ||
371 | + intents.put(leader, createIntent(key, keyPrefix + k, leader, devices)); | ||
372 | + | ||
373 | + // Bump up the counter and remember this as the last key used. | ||
374 | + count++; | ||
375 | + lastKey = k; | ||
376 | + if (count % 1000 == 0) { | ||
377 | + log.info("Building intents... {} (attempt: {})", count, lastKey); | ||
378 | + } | ||
379 | + } | ||
380 | + checkState(intents.values().size() == numberOfKeys, | ||
381 | + "Generated wrong number of intents"); | ||
382 | + log.info("Created {} intents", numberOfKeys); | ||
383 | + intents.keySet().forEach(node -> log.info("\t{}\t{}", node, intents.get(node).size())); | ||
384 | + | ||
385 | + return Sets.newHashSet(intents.values()); | ||
386 | + } | ||
387 | + | ||
388 | + // Submits intent operations. | ||
389 | + final class Submitter implements Runnable { | ||
390 | + | ||
391 | + private long lastDuration; | ||
392 | + private int lastCount; | ||
393 | + | ||
394 | + private Set<Intent> intents = Sets.newHashSet(); | ||
395 | + private Set<Intent> submitted = Sets.newHashSet(); | ||
396 | + private Set<Intent> withdrawn = Sets.newHashSet(); | ||
397 | + | ||
398 | + private Submitter(Set<Intent> intents) { | ||
399 | + this.intents = intents; | ||
400 | + lastCount = numKeys / 4; | ||
401 | + lastDuration = 1_000; // 1 second | ||
402 | + } | ||
403 | + | ||
404 | + @Override | ||
405 | + public void run() { | ||
406 | + prime(); | ||
407 | + while (!stopped) { | ||
408 | + try { | ||
409 | + cycle(); | ||
410 | + } catch (Exception e) { | ||
411 | + log.warn("Exception during cycle", e); | ||
412 | + } | ||
413 | + } | ||
414 | + clear(); | ||
415 | + } | ||
416 | + | ||
417 | + private Iterable<Intent> subset(Set<Intent> intents) { | ||
418 | + List<Intent> subset = Lists.newArrayList(intents); | ||
419 | + Collections.shuffle(subset); | ||
420 | + return subset.subList(0, lastCount); | ||
421 | + } | ||
422 | + | ||
423 | + // Submits the specified intent. | ||
424 | + private void submit(Intent intent) { | ||
425 | + intentService.submit(intent); | ||
426 | + submitted.add(intent); | ||
427 | + withdrawn.remove(intent); //TODO could check result here... | ||
428 | + } | ||
429 | + | ||
430 | + // Withdraws the specified intent. | ||
431 | + private void withdraw(Intent intent) { | ||
432 | + intentService.withdraw(intent); | ||
433 | + withdrawn.add(intent); | ||
434 | + submitted.remove(intent); //TODO could check result here... | ||
435 | + } | ||
436 | + | ||
437 | + // Primes the cycle. | ||
438 | + private void prime() { | ||
439 | + int i = 0; | ||
440 | + withdrawn.addAll(intents); | ||
441 | + for (Intent intent : intents) { | ||
442 | + submit(intent); | ||
443 | + // only submit half of the intents to start | ||
444 | + if (i++ >= intents.size() / 2) { | ||
445 | + break; | ||
446 | + } | ||
447 | + } | ||
448 | + } | ||
449 | + | ||
450 | + private void clear() { | ||
451 | + submitted.forEach(this::withdraw); | ||
452 | + } | ||
453 | + | ||
454 | + // Runs a single operation cycle. | ||
455 | + private void cycle() { | ||
456 | + //TODO consider running without rate adjustment | ||
457 | + adjustRates(); | ||
458 | + | ||
459 | + long start = currentTimeMillis(); | ||
460 | + subset(submitted).forEach(this::withdraw); | ||
461 | + subset(withdrawn).forEach(this::submit); | ||
462 | + long delta = currentTimeMillis() - start; | ||
463 | + | ||
464 | + if (delta > cyclePeriod * 3 || delta < 0) { | ||
465 | + log.warn("Cycle took {} ms", delta); | ||
466 | + } | ||
467 | + | ||
468 | + int difference = cyclePeriod - (int) delta; | ||
469 | + if (difference > 0) { | ||
470 | + delay(difference); | ||
471 | + } | ||
472 | + | ||
473 | + lastDuration = delta; | ||
474 | + } | ||
475 | + | ||
476 | + int cycleCount = 0; | ||
477 | + | ||
478 | + private void adjustRates() { | ||
479 | + | ||
480 | + int addDelta = Math.max(1000 - cycleCount, 10); | ||
481 | + double multRatio = Math.min(0.8 + cycleCount * 0.0002, 0.995); | ||
482 | + | ||
483 | + //FIXME need to iron out the rate adjustment | ||
484 | + //FIXME we should taper the adjustments over time | ||
485 | + //FIXME don't just use the lastDuration, take an average | ||
486 | + if (++cycleCount % 5 == 0) { //TODO: maybe use a timer (we should do this every 5-10 sec) | ||
487 | + if (listener.requestThroughput() - listener.processedThroughput() <= 2000 && //was 500 | ||
488 | + lastDuration <= cyclePeriod) { | ||
489 | + lastCount = Math.min(lastCount + addDelta, intents.size() / 2); | ||
490 | + } else { | ||
491 | + lastCount *= multRatio; | ||
492 | + } | ||
493 | + log.info("last count: {}, last duration: {} ms (sub: {} vs inst: {})", | ||
494 | + lastCount, lastDuration, listener.requestThroughput(), listener.processedThroughput()); | ||
495 | + } | ||
496 | + | ||
497 | + } | ||
498 | + } | ||
499 | + | ||
500 | + // Event listener to monitor throughput. | ||
501 | + final class Listener implements IntentListener { | ||
502 | + | ||
503 | + private final Counter runningTotal = new Counter(); | ||
504 | + private volatile Map<IntentEvent.Type, Counter> counters; | ||
505 | + | ||
506 | + private volatile double processedThroughput = 0; | ||
507 | + private volatile double requestThroughput = 0; | ||
508 | + | ||
509 | + public Listener() { | ||
510 | + counters = initCounters(); | ||
511 | + } | ||
512 | + | ||
513 | + private Map<IntentEvent.Type, Counter> initCounters() { | ||
514 | + Map<IntentEvent.Type, Counter> map = Maps.newHashMap(); | ||
515 | + for (IntentEvent.Type type : IntentEvent.Type.values()) { | ||
516 | + map.put(type, new Counter()); | ||
517 | + } | ||
518 | + return map; | ||
519 | + } | ||
520 | + | ||
521 | + public double processedThroughput() { | ||
522 | + return processedThroughput; | ||
523 | + } | ||
524 | + | ||
525 | + public double requestThroughput() { | ||
526 | + return requestThroughput; | ||
527 | + } | ||
528 | + | ||
529 | + @Override | ||
530 | + public void event(IntentEvent event) { | ||
531 | + if (event.subject().appId().equals(appId)) { | ||
532 | + counters.get(event.type()).add(1); | ||
533 | + } | ||
534 | + } | ||
535 | + | ||
536 | + public void report() { | ||
537 | + Map<IntentEvent.Type, Counter> reportCounters = counters; | ||
538 | + counters = initCounters(); | ||
539 | + | ||
540 | + // update running total and latest throughput | ||
541 | + Counter installed = reportCounters.get(INSTALLED); | ||
542 | + Counter withdrawn = reportCounters.get(WITHDRAWN); | ||
543 | + processedThroughput = installed.throughput() + withdrawn.throughput(); | ||
544 | + runningTotal.add(installed.total() + withdrawn.total()); | ||
545 | + | ||
546 | + Counter installReq = reportCounters.get(INSTALL_REQ); | ||
547 | + Counter withdrawReq = reportCounters.get(WITHDRAW_REQ); | ||
548 | + requestThroughput = installReq.throughput() + withdrawReq.throughput(); | ||
549 | + | ||
550 | + // build the string to report | ||
551 | + StringBuilder stringBuilder = new StringBuilder(); | ||
552 | + for (IntentEvent.Type type : IntentEvent.Type.values()) { | ||
553 | + Counter counter = reportCounters.get(type); | ||
554 | + stringBuilder.append(format("%s=%.2f;", type, counter.throughput())); | ||
555 | + } | ||
556 | + log.info("Throughput: OVERALL={}; CURRENT={}; {}", | ||
557 | + format("%.2f", runningTotal.throughput()), | ||
558 | + format("%.2f", processedThroughput), | ||
559 | + stringBuilder); | ||
560 | + | ||
561 | + sampleCollector.recordSample(runningTotal.throughput(), | ||
562 | + processedThroughput); | ||
563 | + } | ||
564 | + } | ||
565 | + | ||
566 | + private class InternalControl implements ClusterMessageHandler { | ||
567 | + @Override | ||
568 | + public void handle(ClusterMessage message) { | ||
569 | + String cmd = new String(message.payload()); | ||
570 | + log.info("Received command {}", cmd); | ||
571 | + if (cmd.equals(START)) { | ||
572 | + startTestRun(); | ||
573 | + } else { | ||
574 | + stopTestRun(); | ||
575 | + } | ||
576 | + } | ||
577 | + } | ||
578 | + | ||
579 | + private class ReporterTask extends TimerTask { | ||
580 | + @Override | ||
581 | + public void run() { | ||
582 | + //adjustRates(); // FIXME we currently adjust rates in the cycle thread | ||
583 | + listener.report(); | ||
584 | + } | ||
585 | + } | ||
586 | + | ||
587 | +} |
apps/test/intent-perf/src/main/java/org/onosproject/intentperf/IntentPerfListCommand.java
0 → 100644
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onosproject.intentperf; | ||
17 | + | ||
18 | +import org.apache.karaf.shell.commands.Command; | ||
19 | +import org.apache.karaf.shell.commands.Option; | ||
20 | +import org.onosproject.cli.AbstractShellCommand; | ||
21 | +import org.onosproject.intentperf.IntentPerfCollector.Sample; | ||
22 | + | ||
23 | +import java.text.SimpleDateFormat; | ||
24 | +import java.util.Date; | ||
25 | +import java.util.List; | ||
26 | + | ||
27 | +/** | ||
28 | + * Displays accumulated performance metrics. | ||
29 | + */ | ||
30 | +@Command(scope = "onos", name = "intent-perf", | ||
31 | + description = "Displays accumulated performance metrics") | ||
32 | +public class IntentPerfListCommand extends AbstractShellCommand { | ||
33 | + | ||
34 | + @Option(name = "-s", aliases = "--summary", description = "Output just summary", | ||
35 | + required = false, multiValued = false) | ||
36 | + private boolean summary = false; | ||
37 | + | ||
38 | + @Override | ||
39 | + protected void execute() { | ||
40 | + if (summary) { | ||
41 | + printSummary(); | ||
42 | + } else { | ||
43 | + printSamples(); | ||
44 | + } | ||
45 | + } | ||
46 | + | ||
47 | + private void printSummary() { | ||
48 | + IntentPerfCollector collector = get(IntentPerfCollector.class); | ||
49 | + List<String> headers = collector.getSampleHeaders(); | ||
50 | + Sample overall = collector.getOverall(); | ||
51 | + double total = 0; | ||
52 | + print("%12s: %14s", "Node ID", "Overall Rate"); | ||
53 | + for (int i = 0; i < overall.data.length; i++) { | ||
54 | + if (overall.data[i] >= 0) { | ||
55 | + print("%12s: %14.2f", headers.get(i), overall.data[i]); | ||
56 | + total += overall.data[i]; | ||
57 | + } else { | ||
58 | + print("%12s: %14s", headers.get(i), " "); | ||
59 | + } | ||
60 | + } | ||
61 | + print("%12s: %14.2f", "total", total); | ||
62 | + } | ||
63 | + | ||
64 | + private void printSamples() { | ||
65 | + IntentPerfCollector collector = get(IntentPerfCollector.class); | ||
66 | + List<String> headers = collector.getSampleHeaders(); | ||
67 | + List<Sample> samples = collector.getSamples(); | ||
68 | + | ||
69 | + System.out.print(String.format("%10s ", "Time")); | ||
70 | + for (String header : headers) { | ||
71 | + System.out.print(String.format("%12s ", header)); | ||
72 | + } | ||
73 | + System.out.println(String.format("%12s", "Total")); | ||
74 | + | ||
75 | + SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); | ||
76 | + for (Sample sample : samples) { | ||
77 | + double total = 0; | ||
78 | + System.out.print(String.format("%10s ", sdf.format(new Date(sample.time)))); | ||
79 | + for (int i = 0; i < sample.data.length; i++) { | ||
80 | + if (sample.data[i] >= 0) { | ||
81 | + System.out.print(String.format("%12.2f ", sample.data[i])); | ||
82 | + total += sample.data[i]; | ||
83 | + } else { | ||
84 | + System.out.print(String.format("%12s ", " ")); | ||
85 | + } | ||
86 | + } | ||
87 | + System.out.println(String.format("%12.2f", total)); | ||
88 | + } | ||
89 | + } | ||
90 | + | ||
91 | +} |
apps/test/intent-perf/src/main/java/org/onosproject/intentperf/IntentPerfStartCommand.java
0 → 100644
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onosproject.intentperf; | ||
17 | + | ||
18 | +import org.apache.karaf.shell.commands.Command; | ||
19 | +import org.onosproject.cli.AbstractShellCommand; | ||
20 | + | ||
21 | +/** | ||
22 | + * Starts intent performance test run. | ||
23 | + */ | ||
24 | +@Command(scope = "onos", name = "intent-perf-start", | ||
25 | + description = "Starts intent performance test run") | ||
26 | +public class IntentPerfStartCommand extends AbstractShellCommand { | ||
27 | + | ||
28 | + @Override | ||
29 | + protected void execute() { | ||
30 | + get(IntentPerfInstaller.class).start(); | ||
31 | + } | ||
32 | + | ||
33 | +} |
apps/test/intent-perf/src/main/java/org/onosproject/intentperf/IntentPerfStopCommand.java
0 → 100644
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onosproject.intentperf; | ||
17 | + | ||
18 | +import org.apache.karaf.shell.commands.Command; | ||
19 | +import org.onosproject.cli.AbstractShellCommand; | ||
20 | + | ||
21 | +/** | ||
22 | + * Stops intent performance test run. | ||
23 | + */ | ||
24 | +@Command(scope = "onos", name = "intent-perf-stop", | ||
25 | + description = "Stops intent performance test run") | ||
26 | +public class IntentPerfStopCommand extends AbstractShellCommand { | ||
27 | + | ||
28 | + @Override | ||
29 | + protected void execute() { | ||
30 | + get(IntentPerfInstaller.class).stop(); | ||
31 | + } | ||
32 | + | ||
33 | +} |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.onosproject.intentperf; | ||
17 | + | ||
18 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
19 | +import com.google.common.collect.ImmutableList; | ||
20 | +import com.google.common.collect.ImmutableSet; | ||
21 | +import org.apache.felix.scr.annotations.Activate; | ||
22 | +import org.apache.felix.scr.annotations.Component; | ||
23 | +import org.apache.felix.scr.annotations.Deactivate; | ||
24 | +import org.apache.felix.scr.annotations.Reference; | ||
25 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
26 | +import org.onlab.osgi.ServiceDirectory; | ||
27 | +import org.onosproject.intentperf.IntentPerfCollector.Sample; | ||
28 | +import org.onosproject.ui.UiConnection; | ||
29 | +import org.onosproject.ui.UiExtension; | ||
30 | +import org.onosproject.ui.UiExtensionService; | ||
31 | +import org.onosproject.ui.UiMessageHandler; | ||
32 | +import org.onosproject.ui.UiView; | ||
33 | + | ||
34 | +import java.util.Collection; | ||
35 | +import java.util.HashSet; | ||
36 | +import java.util.List; | ||
37 | +import java.util.Set; | ||
38 | + | ||
39 | +import static java.util.Collections.synchronizedSet; | ||
40 | + | ||
41 | +/** | ||
42 | + * Mechanism to stream data to the GUI. | ||
43 | + */ | ||
44 | +@Component(immediate = true, enabled = false) | ||
45 | +public class IntentPerfUi { | ||
46 | + | ||
47 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
48 | + protected UiExtensionService uiExtensionService; | ||
49 | + | ||
50 | + private final Set<StreamingControl> handlers = synchronizedSet(new HashSet<>()); | ||
51 | + | ||
52 | + private List<UiView> views = ImmutableList.of(new UiView("intentPerf", "Intent Performance")); | ||
53 | + private UiExtension uiExtension = new UiExtension(views, this::newHandlers, | ||
54 | + getClass().getClassLoader()); | ||
55 | + | ||
56 | + @Activate | ||
57 | + protected void activate() { | ||
58 | + uiExtensionService.register(uiExtension); | ||
59 | + } | ||
60 | + | ||
61 | + @Deactivate | ||
62 | + protected void deactivate() { | ||
63 | + uiExtensionService.unregister(uiExtension); | ||
64 | + } | ||
65 | + | ||
66 | + /** | ||
67 | + * Reports a single sample of performance data. | ||
68 | + * | ||
69 | + * @param sample performance sample | ||
70 | + */ | ||
71 | + public void reportSample(Sample sample) { | ||
72 | + synchronized (handlers) { | ||
73 | + handlers.forEach(h -> h.send(sample)); | ||
74 | + } | ||
75 | + } | ||
76 | + | ||
77 | + // Creates and returns session specific message handler. | ||
78 | + private Collection<UiMessageHandler> newHandlers() { | ||
79 | + return ImmutableList.of(new StreamingControl()); | ||
80 | + } | ||
81 | + | ||
82 | + // UI Message handlers for turning on/off reporting to a session. | ||
83 | + private class StreamingControl extends UiMessageHandler { | ||
84 | + | ||
85 | + private boolean streamingEnabled = false; | ||
86 | + | ||
87 | + protected StreamingControl() { | ||
88 | + super(ImmutableSet.of("intentPerfStart", "intentPerfStop")); | ||
89 | + } | ||
90 | + | ||
91 | + @Override | ||
92 | + public void process(ObjectNode message) { | ||
93 | + streamingEnabled = message.path("event").asText("unknown").equals("initPerfStart"); | ||
94 | + } | ||
95 | + | ||
96 | + @Override | ||
97 | + public void init(UiConnection connection, ServiceDirectory directory) { | ||
98 | + super.init(connection, directory); | ||
99 | + handlers.add(this); | ||
100 | + } | ||
101 | + | ||
102 | + @Override | ||
103 | + public void destroy() { | ||
104 | + super.destroy(); | ||
105 | + handlers.remove(this); | ||
106 | + } | ||
107 | + | ||
108 | + private void send(Sample sample) { | ||
109 | + // FIXME: finish this | ||
110 | + ObjectNode sn = mapper.createObjectNode() | ||
111 | + .put("time", sample.time); | ||
112 | + connection().sendMessage("intentPerf", 0, sn); | ||
113 | + } | ||
114 | + } | ||
115 | + | ||
116 | +} |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +/** | ||
18 | + * Performance test application that induces steady load on the intent subsystem. | ||
19 | + */ | ||
20 | +package org.onosproject.intentperf; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +<!-- | ||
2 | + ~ Copyright 2015 Open Networking Laboratory | ||
3 | + ~ | ||
4 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + ~ you may not use this file except in compliance with the License. | ||
6 | + ~ You may obtain a copy of the License at | ||
7 | + ~ | ||
8 | + ~ http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + ~ | ||
10 | + ~ Unless required by applicable law or agreed to in writing, software | ||
11 | + ~ distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + ~ See the License for the specific language governing permissions and | ||
14 | + ~ limitations under the License. | ||
15 | + --> | ||
16 | +<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"> | ||
17 | + <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0"> | ||
18 | + <command> | ||
19 | + <action class="org.onosproject.intentperf.IntentPerfListCommand"/> | ||
20 | + </command> | ||
21 | + <command> | ||
22 | + <action class="org.onosproject.intentperf.IntentPerfStartCommand"/> | ||
23 | + </command> | ||
24 | + <command> | ||
25 | + <action class="org.onosproject.intentperf.IntentPerfStopCommand"/> | ||
26 | + </command> | ||
27 | + </command-bundle> | ||
28 | +</blueprint> |
1 | +date,value,node | ||
2 | +00:55:15,68.38,node1 | ||
3 | +00:55:15,55.61,node2 | ||
4 | +00:55:15,74.00,node3 | ||
5 | +00:55:30,74.20,node1 | ||
6 | +00:55:30,77.60,node2 | ||
7 | +00:55:30,74.80,node3 | ||
8 | +00:55:45,74.60,node1 | ||
9 | +00:55:45,72.80,node2 | ||
10 | +00:55:45,77.00,node3 | ||
11 | +00:56:00,73.60,node1 | ||
12 | +00:56:00,75.00,node2 | ||
13 | +00:56:00,76.98,node3 | ||
14 | +00:56:15,75.82,node1 | ||
15 | +00:56:15,75.40,node2 | ||
16 | +00:56:15,76.00,node3 | ||
17 | +00:56:30,75.60,node1 | ||
18 | +00:56:30,74.59,node2 | ||
19 | +00:56:30,74.01,node3 | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +key,value,date | ||
2 | +Group1,37,00:23:00 | ||
3 | +Group2,12,00:23:00 | ||
4 | +Group3,46,00:23:00 | ||
5 | +Group1,32,00:23:05 | ||
6 | +Group2,19,00:23:05 | ||
7 | +Group3,42,00:23:05 | ||
8 | +Group1,45,00:23:10 | ||
9 | +Group2,16,00:23:10 | ||
10 | +Group3,44,00:23:10 | ||
11 | +Group1,24,00:23:15 | ||
12 | +Group2,52,00:23:15 | ||
13 | +Group3,64,00:23:15 | ||
14 | +Group1,34,00:23:20 | ||
15 | +Group2,62,00:23:20 | ||
16 | +Group3,74,00:23:20 | ||
17 | +Group1,34,00:23:25 | ||
18 | +Group2,62,00:23:25 | ||
19 | +Group3,74,00:23:25 | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +/* | ||
18 | + ONOS GUI -- Intent Perf View -- CSS file | ||
19 | + */ | ||
20 | + | ||
21 | +.light #ov-intentPerf { | ||
22 | + color: navy; | ||
23 | +} | ||
24 | + | ||
25 | +.dark #ov-intentPerf { | ||
26 | + color: #1e5e6f; | ||
27 | +} | ||
28 | + | ||
29 | +.dark a { | ||
30 | + color: #88c; | ||
31 | +} | ||
32 | + | ||
33 | +#ov-intentPerf .msg { | ||
34 | + color: darkorange; | ||
35 | +} | ||
36 | + | ||
37 | +.light #ov-intentPerf .msg { | ||
38 | + color: darkorange; | ||
39 | +} | ||
40 | + | ||
41 | +.dark #ov-intentPerf .msg { | ||
42 | + color: #904e00; | ||
43 | +} | ||
44 | + | ||
45 | + | ||
46 | + | ||
47 | +.axis path, | ||
48 | +.axis line { | ||
49 | + fill: none; | ||
50 | + stroke: #000; | ||
51 | + shape-rendering: crispEdges; | ||
52 | +} | ||
53 | + | ||
54 | +.browser text { | ||
55 | + text-anchor: end; | ||
56 | +} |
1 | +<!-- | ||
2 | + ~ Copyright 2015 Open Networking Laboratory | ||
3 | + ~ | ||
4 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + ~ you may not use this file except in compliance with the License. | ||
6 | + ~ You may obtain a copy of the License at | ||
7 | + ~ | ||
8 | + ~ http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + ~ | ||
10 | + ~ Unless required by applicable law or agreed to in writing, software | ||
11 | + ~ distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + ~ See the License for the specific language governing permissions and | ||
14 | + ~ limitations under the License. | ||
15 | + --> | ||
16 | + | ||
17 | +<!-- Intent Performance partial HTML --> | ||
18 | +<div id="ov-sample"> | ||
19 | + <h2> Intent Performance View </h2> | ||
20 | + | ||
21 | + <span class="msg">{{ ctrl.message }}</span> | ||
22 | + | ||
23 | + <div id="intent-perf-chart"></div> | ||
24 | +</div> |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +/* | ||
18 | + ONOS GUI -- Intent Performance View Module | ||
19 | + */ | ||
20 | +(function () { | ||
21 | + 'use strict'; | ||
22 | + | ||
23 | + // injected refs | ||
24 | + var $log, tbs, flash; | ||
25 | + | ||
26 | + function start() { | ||
27 | + //var format = d3.time.format("%m/%d/%y"); | ||
28 | + var format = d3.time.format("%H:%M:%S"); | ||
29 | + var samples = []; | ||
30 | + | ||
31 | + var margin = {top: 20, right: 30, bottom: 30, left: 40}, | ||
32 | + width = 960 - margin.left - margin.right, | ||
33 | + height = 500 - margin.top - margin.bottom; | ||
34 | + | ||
35 | + var x = d3.time.scale() | ||
36 | + .range([0, width]); | ||
37 | + | ||
38 | + var y = d3.scale.linear() | ||
39 | + .range([height, 0]); | ||
40 | + | ||
41 | + var z = d3.scale.category20c(); | ||
42 | + | ||
43 | + var xAxis = d3.svg.axis() | ||
44 | + .scale(x) | ||
45 | + .orient("bottom") | ||
46 | + .ticks(d3.time.seconds); | ||
47 | + | ||
48 | + var yAxis = d3.svg.axis() | ||
49 | + .scale(y) | ||
50 | + .orient("left"); | ||
51 | + | ||
52 | + var stack = d3.layout.stack() | ||
53 | + .offset("zero") | ||
54 | + .values(function(d) { return d.values; }) | ||
55 | + .x(function(d) { return d.date; }) | ||
56 | + .y(function(d) { return d.value; }); | ||
57 | + | ||
58 | + var nest = d3.nest() | ||
59 | + .key(function(d) { return d.key; }); | ||
60 | + | ||
61 | + var area = d3.svg.area() | ||
62 | + .interpolate("cardinal") | ||
63 | + .x(function(d) { return x(d.date); }) | ||
64 | + .y0(function(d) { return y(d.y0); }) | ||
65 | + .y1(function(d) { return y(d.y0 + d.y); }); | ||
66 | + | ||
67 | + var svg = d3.select("body").append("svg") | ||
68 | + .attr("width", width + margin.left + margin.right) | ||
69 | + .attr("height", height + margin.top + margin.bottom) | ||
70 | + .append("g") | ||
71 | + .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | ||
72 | + | ||
73 | + svg.append("g") | ||
74 | + .attr("class", "x axis") | ||
75 | + .attr("transform", "translate(0," + height + ")") | ||
76 | + .call(xAxis); | ||
77 | + | ||
78 | + svg.append("g") | ||
79 | + .attr("class", "y axis") | ||
80 | + .call(yAxis); | ||
81 | + | ||
82 | + function fetchData() { | ||
83 | + d3.csv("app/view/intentPerf/data.csv", function (data) { | ||
84 | + samples = data; | ||
85 | + updateGraph(); | ||
86 | + }); | ||
87 | + } | ||
88 | + | ||
89 | + function updateGraph() { | ||
90 | + samples.forEach(function(d) { | ||
91 | + d.date = format.parse(d.date); | ||
92 | + d.value = +d.value; | ||
93 | + }); | ||
94 | + | ||
95 | + var layers = stack(nest.entries(samples)); | ||
96 | + | ||
97 | + x.domain(d3.extent(samples, function(d) { return d.date; })); | ||
98 | + y.domain([0, d3.max(samples, function(d) { return d.y0 + d.y; })]); | ||
99 | + | ||
100 | + svg.selectAll(".layer") | ||
101 | + .data(layers) | ||
102 | + .enter().append("path") | ||
103 | + .attr("class", "layer") | ||
104 | + .attr("d", function(d) { return area(d.values); }) | ||
105 | + .style("fill", function(d, i) { return z(i); }); | ||
106 | + | ||
107 | + svg.select(".x") | ||
108 | + .attr("transform", "translate(0," + height + ")") | ||
109 | + .call(xAxis); | ||
110 | + | ||
111 | + svg.select(".y") | ||
112 | + .call(yAxis); | ||
113 | + | ||
114 | + console.log('tick'); | ||
115 | + } | ||
116 | + } | ||
117 | + | ||
118 | + start(); | ||
119 | + | ||
120 | + // define the controller | ||
121 | + | ||
122 | + angular.module('ovIntentPerf', ['onosUtil']) | ||
123 | + .controller('OvIntentPerfCtrl', | ||
124 | + ['$scope', '$log', 'ToolbarService', 'FlashService', | ||
125 | + | ||
126 | + function ($scope, _$log_, _tbs_, _flash_) { | ||
127 | + var self = this | ||
128 | + | ||
129 | + $log = _$log_; | ||
130 | + tbs = _tbs_; | ||
131 | + flash = _flash_; | ||
132 | + | ||
133 | + self.message = 'Hey there dudes!'; | ||
134 | + start(); | ||
135 | + | ||
136 | + // Clean up on destroyed scope | ||
137 | + $scope.$on('$destroy', function () { | ||
138 | + }); | ||
139 | + | ||
140 | + $log.log('OvIntentPerfCtrl has been created'); | ||
141 | + }]); | ||
142 | +}()); |
1 | +<link rel="stylesheet" href="app/view/intentPerf/intentPerf.css"> |
1 | +<!DOCTYPE html> | ||
2 | +<!-- | ||
3 | + ~ Copyright 2014 Open Networking Laboratory | ||
4 | + ~ | ||
5 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + ~ you may not use this file except in compliance with the License. | ||
7 | + ~ You may obtain a copy of the License at | ||
8 | + ~ | ||
9 | + ~ http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + ~ | ||
11 | + ~ Unless required by applicable law or agreed to in writing, software | ||
12 | + ~ distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + ~ See the License for the specific language governing permissions and | ||
15 | + ~ limitations under the License. | ||
16 | + --> | ||
17 | +<html> | ||
18 | +<head> | ||
19 | + <title>Dev View</title> | ||
20 | + <script src="tp/d3.min.js"></script> | ||
21 | + <script src="tp/jquery-2.1.1.min.js"></script> | ||
22 | + | ||
23 | + <link rel="stylesheet" href="app/view/intentPerf/intentPerf.css"> | ||
24 | +</head> | ||
25 | +<body> | ||
26 | +<div id="intent-perf-chart" style="width: 1024px; height: 800px"></div> | ||
27 | +<script src="app/view/intentPerf/intentPerf.js"></script> | ||
28 | +</body> | ||
29 | +</html> | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +<script src="app/view/intentPerf/intentPerf.js"></script> |
apps/test/pom.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
2 | +<!-- | ||
3 | + ~ Copyright 2015 Open Networking Laboratory | ||
4 | + ~ | ||
5 | + ~ Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + ~ you may not use this file except in compliance with the License. | ||
7 | + ~ You may obtain a copy of the License at | ||
8 | + ~ | ||
9 | + ~ http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + ~ | ||
11 | + ~ Unless required by applicable law or agreed to in writing, software | ||
12 | + ~ distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + ~ See the License for the specific language governing permissions and | ||
15 | + ~ limitations under the License. | ||
16 | + --> | ||
17 | +<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
18 | + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
19 | + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
20 | + <modelVersion>4.0.0</modelVersion> | ||
21 | + | ||
22 | + <parent> | ||
23 | + <groupId>org.onosproject</groupId> | ||
24 | + <artifactId>onos</artifactId> | ||
25 | + <version>1.2.0-SNAPSHOT</version> | ||
26 | + <relativePath>../pom.xml</relativePath> | ||
27 | + </parent> | ||
28 | + | ||
29 | + <artifactId>onos-apps-test</artifactId> | ||
30 | + <packaging>pom</packaging> | ||
31 | + | ||
32 | + <description>ONOS test applications</description> | ||
33 | + | ||
34 | + <modules> | ||
35 | + <module>election</module> | ||
36 | + <module>intent-perf</module> | ||
37 | + </modules> | ||
38 | + | ||
39 | +</project> |
-
Please register or login to post a comment