Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CODETOOLS-7902980: jcstress: Scheduler fails on irregular architectures #82

Merged
merged 2 commits into from
Jun 21, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions jcstress-core/pom.xml
Original file line number Diff line number Diff line change
@@ -60,9 +60,9 @@ questions.
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<forkCount>1C</forkCount>
<reuseForks>false</reuseForks>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
<threadCount>1</threadCount>
<perCoreThreadCount>true</perCoreThreadCount>
<parallel>classes</parallel>
</configuration>
</plugin>
<plugin>
Original file line number Diff line number Diff line change
@@ -161,7 +161,7 @@ private CPUMap scheduleLocal(SchedulingClass scl) {
}

// Roll over the sibling threads and allow them too for system uses
int[] system = new int[scl.numCores()*topology.threadsPerCore()];
int[] system = new int[topology.totalThreads()];
int systemCnt = 0;
for (int core : coreGroupToCore) {
for (int thread : topology.coreThreads(core)) {
@@ -221,7 +221,7 @@ private CPUMap scheduleGlobal(SchedulingClass scl) {
}

// Take all affected cores as system assignment
int[] system = new int[scl.numActors()*topology.threadsPerCore()];
int[] system = new int[topology.totalThreads()];
int systemCnt = 0;

for (int core : actorToCore) {
Original file line number Diff line number Diff line change
@@ -28,7 +28,7 @@

import java.io.PrintStream;

public class FallbackTopology extends PresetTopology {
public class FallbackTopology extends PresetRegularTopology {

public FallbackTopology() throws TopologyParseException {
super(1, VMSupport.figureOutHotCPUs(), 1);
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (c) 2021, Red Hat, Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.openjdk.jcstress.os.topology;

public class PresetListTopology extends AbstractTopology {

public void add(int packageId, int coreId, int threadId) throws TopologyParseException {
super.add(packageId, coreId, threadId);
}

public void finish() throws TopologyParseException {
super.finish();
}

}
Original file line number Diff line number Diff line change
@@ -24,9 +24,9 @@
*/
package org.openjdk.jcstress.os.topology;

public class PresetTopology extends AbstractTopology {
public class PresetRegularTopology extends AbstractTopology {

public PresetTopology(int packagesPerSystem, int coresPerPackage, int threadsPerCore) throws TopologyParseException {
public PresetRegularTopology(int packagesPerSystem, int coresPerPackage, int threadsPerCore) throws TopologyParseException {
for (int t = 0; t < threadsPerCore; t++) {
for (int p = 0; p < packagesPerSystem; p++) {
for (int c = 0; c < coresPerPackage; c++) {
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Red Hat, Inc. All rights reserved.
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,52 +25,48 @@
package org.openjdk.jcstress.os;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.openjdk.jcstress.os.topology.PresetTopology;
import org.openjdk.jcstress.os.topology.PresetRegularTopology;
import org.openjdk.jcstress.os.topology.Topology;
import org.openjdk.jcstress.os.topology.TopologyParseException;

import java.util.*;
import java.util.concurrent.LinkedBlockingQueue;

@RunWith(Parameterized.class)
public class SchedulerLocalAffinityTest {

@Parameterized.Parameters(name = "p={0} c={1} t={2} limited={3}")
public static Iterable<Object[]> data() {
List<Object[]> r = new ArrayList<>();
for (int p = 1; p <= 4; p++) {
for (int c : new int[] { 1, 2, 4, 5, 6, 8 }) {
for (int t : new int[] { 1, 2, 8 }) {
r.add(new Object[] { p, c, t, false });
r.add(new Object[] { p, c, t, true });
}
public class AbstractSchedulerAffinityTest {

public void runGlobal(Scheduler s, int maxThreads) {
Queue<CPUMap> takenMaps = new LinkedBlockingQueue<>();

List<SchedulingClass> cases = new ArrayList<>();
for (int a = 1; a <= 4; a++) {
List<SchedulingClass> skel = s.globalAffinityFor(a, maxThreads);
for (int c = 0; c < 1000; c++) {
cases.addAll(skel);
}
}
return r;
}

@Parameterized.Parameter(0)
public int p;

@Parameterized.Parameter(1)
public int c;
Collections.shuffle(cases, new Random(12345));

@Parameterized.Parameter(2)
public int t;
for (SchedulingClass scl : cases) {
CPUMap cpuMap = s.tryAcquire(scl);
while (cpuMap == null) {
CPUMap old = takenMaps.poll();
Assert.assertNotNull("Cannot schedule on empty system", old);
s.release(old);
cpuMap = s.tryAcquire(scl);
}

@Parameterized.Parameter(3)
public boolean limited;
takenMaps.offer(cpuMap);

@Test
public void test() throws TopologyParseException {
Topology topo = new PresetTopology(p, c, t);
int maxThreads = limited ? Math.min(4, topo.totalCores()) : topo.totalCores();
Scheduler s = new Scheduler(topo, maxThreads);
s.enableDebug();
Assert.assertEquals(scl.numActors(), cpuMap.actorMap().length);
for (int c : cpuMap.actorMap()) {
Assert.assertEquals(-1, c);
}
Assert.assertNotEquals(0, cpuMap.systemMap().length);
}
}

public void runLocal(Topology topo, Scheduler s, int maxThreads) {
Queue<CPUMap> takenMaps = new LinkedBlockingQueue<>();

List<SchedulingClass> cases = new ArrayList<>();
@@ -116,4 +112,35 @@ public void test() throws TopologyParseException {
}
}

public void runNone(Topology topo, Scheduler s, int maxThreads) {
Queue<CPUMap> takenMaps = new LinkedBlockingQueue<>();

List<SchedulingClass> cases = new ArrayList<>();
for (int a = 1; a <= 4; a++) {
List<SchedulingClass> skel = s.noneAffinityFor(a, maxThreads);
for (int c = 0; c < 1000; c++) {
cases.addAll(skel);
}
}

Collections.shuffle(cases, new Random(12345));

for (SchedulingClass scl : cases) {
CPUMap cpuMap = s.tryAcquire(scl);
while (cpuMap == null) {
CPUMap old = takenMaps.poll();
Assert.assertNotNull("Cannot schedule on empty system: " + scl, old);
s.release(old);
cpuMap = s.tryAcquire(scl);
}

takenMaps.offer(cpuMap);
Assert.assertEquals(scl.numActors(), cpuMap.actorMap().length);
for (int c : cpuMap.actorMap()) {
Assert.assertEquals(-1, c);
}
Assert.assertNotEquals(0, cpuMap.systemMap().length);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Copyright (c) 2021, Red Hat, Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.openjdk.jcstress.os;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.openjdk.jcstress.os.topology.PresetListTopology;
import org.openjdk.jcstress.os.topology.TopologyParseException;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

@RunWith(Parameterized.class)
public class SchedulerAffinityIrregularTest extends AbstractSchedulerAffinityTest {

@Parameterized.Parameters(name = "n={0}")
public static Iterable<Object[]> data() {
List<Object[]> r = new ArrayList<>();
for (int n = 0; n < 2048; n++) {
r.add(new Object[] { n });
}
return r;
}

@Parameterized.Parameter(0)
public int n;

@Test
public void test_Local() throws TopologyParseException {
PresetListTopology topo = generate();

int maxThreads = topo.totalThreads();
Scheduler s = new Scheduler(topo, maxThreads);
s.enableDebug();

runLocal(topo, s, maxThreads);
}

@Test
public void test_Global() throws TopologyParseException {
PresetListTopology topo = generate();

int maxThreads = topo.totalThreads();
Scheduler s = new Scheduler(topo, maxThreads);
s.enableDebug();

runGlobal(s, maxThreads);
}

@Test
public void test_None() throws TopologyParseException {
PresetListTopology topo = generate();

int maxThreads = topo.totalThreads();
Scheduler s = new Scheduler(topo, maxThreads);
s.enableDebug();

runNone(topo, s, maxThreads);
}

private PresetListTopology generate() throws TopologyParseException {
Random r = new Random(n);

PresetListTopology topo = new PresetListTopology();

int pId = 0;
int cId = 0;
int tId = 0;
for (int c = 0; c < 10; c++) {
topo.add(pId, cId, tId);

tId++;
if (r.nextInt(10) > 8) {
cId++;
} else if (r.nextInt(10) > 8) {
pId++;
cId++;
}
}
topo.finish();
return topo;
}
}
Loading