AlibabaSchedulerEvaluatorRun.java 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. package com.aliyun.tianchi.mgr.evaluate.evaluate.file.evaluator;
  2. import java.io.BufferedReader;
  3. import java.io.ByteArrayInputStream;
  4. import java.io.File;
  5. import java.io.FileInputStream;
  6. import java.io.FileReader;
  7. import java.io.IOException;
  8. import java.io.InputStream;
  9. import java.io.InputStreamReader;
  10. import java.util.ArrayList;
  11. import java.util.HashMap;
  12. import java.util.HashSet;
  13. import java.util.List;
  14. import java.util.Map;
  15. import java.util.Set;
  16. import org.apache.commons.lang3.tuple.ImmutablePair;
  17. import org.apache.commons.lang3.tuple.Pair;
  18. import com.google.common.base.Charsets;
  19. /**
  20. * Created by mou.sunm on 2018/08/19.
  21. */
  22. public class AlibabaSchedulerEvaluatorRun {
  23. // 参数
  24. public static final double beta = 0.5;
  25. public static final int T2 = 98 * 15;
  26. public static final int EXEC_LIMIT = 3;
  27. private List<Problem> problems;
  28. // 主函数
  29. public static void main(String[] args) throws Exception {
  30. if (args.length != 6 && args.length != 2) {
  31. System.err.println("传入参数有误,使用方式为:");
  32. System.err.println(
  33. "\t\tjava -cp xxx.jar com.aliyun.tianchi.mgr.evaluate.evaluate.file.evaluator.AlibabaSchedulerEvaluatorRun app_resources.csv machine_resources.csv instance_deploy.csv app_interference.csv job_info.csv result.csv");
  34. System.err.println("或:");
  35. System.err.println(
  36. "\t\tjava -cp xxx.jar com.aliyun.tianchi.mgr.evaluate.evaluate.file.evaluator.AlibabaSchedulerEvaluatorRun judge.csv result.csv");
  37. return;
  38. }
  39. InputStream problemIS;
  40. InputStream resultIS;
  41. if (args.length == 6) {
  42. // 将赛题拼成评测数据
  43. StringBuffer sb = new StringBuffer();
  44. for (int i = 0; i < 5; i++) {
  45. List<String> lines = new ArrayList<String>();
  46. BufferedReader bs = new BufferedReader(new FileReader(new File(args[i])));
  47. for (String line = bs.readLine(); line != null; line = bs.readLine())
  48. lines.add(line);
  49. bs.close();
  50. sb.append("" + lines.size());
  51. for (String line : lines)
  52. sb.append("\n").append(line);
  53. if (i != 4)
  54. sb.append("\n");
  55. }
  56. String alldata = sb.toString();
  57. problemIS = new ByteArrayInputStream(alldata.getBytes());
  58. resultIS = new FileInputStream(args[5]);
  59. } else {
  60. problemIS = new FileInputStream(args[0]);
  61. resultIS = new FileInputStream(args[1]);
  62. }
  63. // 评测
  64. AlibabaSchedulerEvaluatorRun evaluator = new AlibabaSchedulerEvaluatorRun();
  65. evaluator.init(new BufferedReader(new InputStreamReader(problemIS, Charsets.UTF_8)));
  66. double score = evaluator.evaluate(new BufferedReader(new InputStreamReader(resultIS, Charsets.UTF_8)));
  67. System.out.println("选手所得分数为:" + score);
  68. }
  69. // 评测问题
  70. protected double evaluate(BufferedReader bufferedReader) throws IOException {
  71. double costs = 0.;
  72. for (int iter = 0; iter < problems.size(); iter++) {
  73. System.out.print("正在评测第" + iter + "份数据, 得分:");
  74. double cost = problems.get(iter).evaluate(bufferedReader);
  75. costs += cost;
  76. System.out.println("" + cost);
  77. }
  78. return costs / problems.size();
  79. }
  80. // 读取数据
  81. protected void init(BufferedReader bufferedReader) throws IOException {
  82. problems = new ArrayList<Problem>();
  83. while (true) {
  84. String firstLine = bufferedReader.readLine();
  85. if (firstLine == null)
  86. break;
  87. System.out.print("正在读取第" + problems.size() + "份数据");
  88. Problem prob = new Problem();
  89. prob.init(firstLine, bufferedReader);
  90. problems.add(prob);
  91. System.out.println(",成功");
  92. }
  93. }
  94. class Problem {
  95. // 静态数据
  96. private int n; // app数
  97. private int N; // inst数
  98. private int m; // machine数
  99. private int k = 2 * T2 + 4; // 资源种类
  100. private Map<String, Integer> appIndex;
  101. private Map<String, Integer> machineIndex;
  102. private String[] apps;
  103. private String[] machines;
  104. private Map<String, Integer> inst2AppIndex;
  105. private double[][] appResources;
  106. private double[][] machineResources;
  107. private Map<Integer, Integer>[] appInterference;
  108. private String[] jobs;
  109. private int jobN;
  110. private Map<String, Integer> jobIndex;
  111. private double[][] jobResources;
  112. private int[] jobR;
  113. private int[] jobV;
  114. private Set<Integer>[] jobFa;
  115. // 动态数据
  116. private Map<String, Integer> inst2Machine;
  117. private double[][] machineResourcesUsed;
  118. private Map<Integer, Integer>[] machineHasApp;
  119. public void init(String firstLine, BufferedReader bufferedReader) throws IOException {
  120. /** Read app_resources */
  121. n = Integer.parseInt(firstLine);// 9338
  122. apps = new String[n];
  123. appIndex = new HashMap<String, Integer>();
  124. appResources = new double[n][k];
  125. for (int i = 0; i < n; i++) {
  126. // appId,resources
  127. String line = bufferedReader.readLine();
  128. String[] parts = line.split(",", -1);
  129. List<Double> resources = new ArrayList<Double>();
  130. for (String x : parts[1].split("\\|", -1)) {
  131. double cpu = Double.parseDouble(x);
  132. for (int tt = 0; tt < 15; tt++)
  133. resources.add(cpu);
  134. }
  135. for (String x : parts[2].split("\\|", -1)) {
  136. double mem = Double.parseDouble(x);
  137. for (int tt = 0; tt < 15; tt++)
  138. resources.add(mem);
  139. }
  140. for (int j = 3; j < parts.length; j++)
  141. resources.add(Double.parseDouble(parts[j]));
  142. if (k != resources.size())
  143. throw new IOException("[DEBUG 2]Invaild problem: " + k + ", " + resources.size());
  144. if (appIndex.containsKey(parts[0]))
  145. throw new IOException("[DEBUG 3]Invaild problem");
  146. appIndex.put(parts[0], i);
  147. apps[i] = parts[0];
  148. for (int j = 0; j < k; j++)
  149. appResources[i][j] = resources.get(j);
  150. }
  151. /** Read machine_resources */
  152. m = Integer.parseInt(bufferedReader.readLine());// 8000
  153. machineResources = new double[m][k];
  154. machineResourcesUsed = new double[m][k];
  155. machineIndex = new HashMap<String, Integer>();
  156. machineHasApp = new Map[m];
  157. machines = new String[m];
  158. for (int i = 0; i < m; i++) {
  159. // machineId,resources
  160. String line = bufferedReader.readLine();
  161. String[] parts = line.split(",", -1);
  162. if (machineIndex.containsKey(parts[0]))
  163. throw new IOException("[DEBUG 4]Invaild problem");
  164. machineIndex.put(parts[0], i);
  165. machines[i] = parts[0];
  166. machineHasApp[i] = new HashMap<Integer, Integer>();
  167. double cpu = Double.parseDouble(parts[1]);
  168. double mem = Double.parseDouble(parts[2]);
  169. for (int j = 0; j < T2; j++) {
  170. machineResources[i][j] = cpu;
  171. machineResources[i][T2 + j] = mem;
  172. }
  173. for (int j = 3; j < parts.length; j++)
  174. machineResources[i][2 * T2 + j - 3] = Double.parseDouble(parts[j]);
  175. for (int j = 0; j < k; j++)
  176. machineResourcesUsed[i][j] = 0.;
  177. }
  178. /** Read instance_deploy */
  179. N = Integer.parseInt(bufferedReader.readLine());
  180. inst2AppIndex = new HashMap<String, Integer>();
  181. inst2Machine = new HashMap<String, Integer>();
  182. for (int i = 0; i < N; i++) {
  183. String line = bufferedReader.readLine();
  184. String[] parts = line.split(",", -1);
  185. if (inst2AppIndex.containsKey(parts[0]))
  186. throw new IOException("[DEBUG 5]Invaild problem");
  187. if (!appIndex.containsKey(parts[1]))
  188. throw new IOException("[DEBUG 6]Invaild problem");
  189. inst2AppIndex.put(parts[0], appIndex.get(parts[1]));
  190. if (!"".equals(parts[2])) {
  191. if (!machineIndex.containsKey(parts[2]))
  192. throw new IOException("[DEBUG 7]Invaild problem");
  193. toMachine(parts[0], machineIndex.get(parts[2]), false);
  194. }
  195. }
  196. /** Read app_interference */
  197. int icnt = Integer.parseInt(bufferedReader.readLine());
  198. appInterference = new Map[n];
  199. for (int i = 0; i < n; i++)
  200. appInterference[i] = new HashMap<Integer, Integer>();
  201. for (int i = 0; i < icnt; i++) {
  202. String line = bufferedReader.readLine();
  203. String[] parts = line.split(",", -1);
  204. if (!appIndex.containsKey(parts[0]) || !appIndex.containsKey(parts[1]))
  205. throw new IOException("[DEBUG 8]Invaild problem");
  206. int app1 = appIndex.get(parts[0]);
  207. int app2 = appIndex.get(parts[1]);
  208. int limit = Integer.parseInt(parts[2]);
  209. Map<Integer, Integer> inter = appInterference[app1];
  210. if (inter.containsKey(app2))
  211. throw new IOException("[DEBUG 9]Invaild problem");
  212. if (app1 == app2)
  213. limit += 1; // self-interference +1 here
  214. inter.put(app2, limit);
  215. }
  216. /** Read job_info */
  217. jobN = Integer.parseInt(bufferedReader.readLine());
  218. jobs = new String[jobN];
  219. jobIndex = new HashMap<String, Integer>();
  220. jobResources = new double[jobN][2];
  221. jobV = new int[jobN];
  222. jobR = new int[jobN];
  223. jobFa = new Set[jobN];
  224. Set<String>[] tFa = new Set[jobN];
  225. for (int i = 0; i < jobN; i++) {
  226. tFa[i] = new HashSet<String>();
  227. String line = bufferedReader.readLine();
  228. String[] parts = line.split(",", -1);
  229. if (jobIndex.containsKey(parts[0]))
  230. throw new IOException("[DEBUG 10]Invaild problem");
  231. jobIndex.put(parts[0], i);
  232. jobs[i] = parts[0];
  233. jobResources[i][0] = Double.parseDouble(parts[1]);
  234. jobResources[i][1] = Double.parseDouble(parts[2]);
  235. jobV[i] = Integer.parseInt(parts[3]);
  236. jobR[i] = Integer.parseInt(parts[4]);
  237. if (jobV[i] <= 0 || jobR[i] <= 0)
  238. throw new IOException("[DEBUG 10.1]Invaild problem");
  239. for (int it = 5; it < parts.length; it++)
  240. tFa[i].add(parts[it]);
  241. }
  242. for (int i = 0; i < jobN; i++) {
  243. jobFa[i] = new HashSet<Integer>();
  244. for (String job : tFa[i]) {
  245. if (!jobIndex.containsKey(job))
  246. continue;
  247. jobFa[i].add(jobIndex.get(job));
  248. }
  249. }
  250. }
  251. public double evaluate(BufferedReader bufferedReader) throws IOException {
  252. double costs = 0.;
  253. try {
  254. /** 读取执行数据 */
  255. List<Pair<String, Integer>>[] execs = new List[EXEC_LIMIT + 1];
  256. for (int i = 1; i <= EXEC_LIMIT; i++)//3
  257. execs[i] = new ArrayList<Pair<String, Integer>>();
  258. List<Pair<Integer, Integer>> jobExec = new ArrayList<Pair<Integer, Integer>>();
  259. List<Pair<Integer, Integer>> jobExecDetail = new ArrayList<Pair<Integer, Integer>>();
  260. boolean readFail = false;
  261. boolean jobExecStart = false;
  262. for (String line = bufferedReader.readLine(); line != null
  263. && !line.equals("#"); line = bufferedReader.readLine()) {
  264. String[] pair = line.split(",", -1);
  265. if ((pair.length != 3 && pair.length != 4) || (pair.length == 3 && jobExecStart)) {
  266. System.out.println("Read failed: " + line);
  267. readFail = true;
  268. continue;
  269. }
  270. if (pair.length == 3) {
  271. int stage = Integer.parseInt(pair[0]);
  272. if (stage < 1 || stage > EXEC_LIMIT || !inst2AppIndex.containsKey(pair[1])
  273. || !machineIndex.containsKey(pair[2])) {
  274. System.out.println("" + (stage < 1) + ", " + (stage > EXEC_LIMIT) + ", "
  275. + (!inst2AppIndex.containsKey(pair[1])) + ", "
  276. + (!machineIndex.containsKey(pair[2])));
  277. readFail = true;
  278. continue;
  279. }
  280. execs[stage].add(new ImmutablePair(pair[1], machineIndex.get(pair[2])));
  281. } else {
  282. jobExecStart = true;
  283. if (!jobIndex.containsKey(pair[0]) || !machineIndex.containsKey(pair[1])) {
  284. System.out.println("" + (!jobIndex.containsKey(pair[0])) + ", "
  285. + (!machineIndex.containsKey(pair[1])));
  286. readFail = true;
  287. continue;
  288. }
  289. jobExec.add(new ImmutablePair(jobIndex.get(pair[0]), machineIndex.get(pair[1])));
  290. jobExecDetail.add(new ImmutablePair(Integer.parseInt(pair[2]), Integer.parseInt(pair[3])));
  291. }
  292. }
  293. if (readFail)
  294. throw new Exception("Invaild solution file");
  295. /** app exec */
  296. for (int stage = 1; stage <= EXEC_LIMIT; stage++) {
  297. /** 记录pickFrom */
  298. Map<String, Integer> pickFrom = new HashMap<String, Integer>();
  299. for (Pair<String, Integer> exec : execs[stage]) {
  300. String inst = exec.getLeft();
  301. if (!inst2Machine.containsKey(inst))
  302. continue;
  303. int fromMachine = inst2Machine.get(inst);
  304. if (pickFrom.containsKey(inst))
  305. throw new Exception("duplicate instance: " + inst);
  306. pickFrom.put(inst, fromMachine);
  307. }
  308. /** 执行 */
  309. for (Pair<String, Integer> exec : execs[stage]) {
  310. String inst = exec.getLeft();
  311. Integer machineIt = exec.getRight();
  312. String msg = toMachine(inst, machineIt);
  313. if (!msg.equals("success"))
  314. throw new Exception("执行失败, inst: " + inst + ", stage: " + stage + ", msg: " + msg);
  315. }
  316. /** 清理 */
  317. for (String inst : pickFrom.keySet()) {
  318. int machineIt = pickFrom.get(inst);
  319. pickInstance(inst, machineIt);
  320. }
  321. }
  322. /** job exec */
  323. int[] jobAsigned = new int[jobN];
  324. int[] jobFirstStart = new int[jobN];
  325. int[] jobLastEnd = new int[jobN];
  326. Set<Integer> hasJob = new HashSet<Integer>();
  327. for (int i = 0; i < jobN; i++) {
  328. jobAsigned[i] = 0;
  329. jobFirstStart[i] = T2;
  330. jobLastEnd[i] = -1;
  331. }
  332. for (int it = 0; it < jobExec.size(); it++) {
  333. int job = jobExec.get(it).getLeft();
  334. int machineIt = jobExec.get(it).getRight();
  335. int start = jobExecDetail.get(it).getLeft();
  336. int cnt = jobExecDetail.get(it).getRight();
  337. int end = start + jobR[job] - 1;
  338. if (end >= T2 || start < 0)
  339. throw new Exception("job TLE, job:" + jobs[job] + ", start:" + start);
  340. if (cnt <= 0)
  341. throw new Exception("job assignment <= 0");
  342. hasJob.add(machineIt);
  343. jobAsigned[job] += cnt;
  344. jobFirstStart[job] = Math.min(jobFirstStart[job], start);
  345. jobLastEnd[job] = Math.max(jobLastEnd[job], end);
  346. for (int i = start; i <= end; i++) {
  347. machineResourcesUsed[machineIt][i] += jobResources[job][0];
  348. machineResourcesUsed[machineIt][T2 + i] += jobResources[job][1];
  349. }
  350. }
  351. /** 计算终态得分 */
  352. // 检查inst是否全部放入machine
  353. for (String inst : inst2AppIndex.keySet())
  354. if (!inst2Machine.containsKey(inst))
  355. throw new Exception("instance未全部分配, " + inst);
  356. // 检查job是否全部放入machine
  357. for (int job = 0; job < jobN; job++)
  358. if (jobAsigned[job] != jobV[job])
  359. throw new Exception("job未全部分配, " + jobs[job]);
  360. // 检查job是否满足DAG
  361. for (int job = 0; job < jobN; job++)
  362. for (Integer fa : jobFa[job])
  363. if (jobFirstStart[job] <= jobLastEnd[fa])
  364. throw new Exception("DAG broken: " + jobs[fa] + ":" + jobLastEnd[fa] + " -> " + jobs[job]
  365. + ":" + jobFirstStart[job]);
  366. // 检查machine的终态
  367. for (int j = 0; j < m; j++) {
  368. Map<Integer, Integer> hasApp = machineHasApp[j];
  369. if (hasApp.size() == 0 && !hasJob.contains(j))
  370. continue;
  371. // 检查互斥条件
  372. int appCnt = 0;
  373. for (Integer conditionalApp : hasApp.keySet()) {
  374. if (hasApp.get(conditionalApp) <= 0)
  375. throw new Exception("[DEBUG 1]Stupid Judger.");
  376. appCnt += hasApp.get(conditionalApp);
  377. for (Integer checkApp : appInterference[conditionalApp].keySet()) {
  378. if (hasApp.containsKey(checkApp)) {
  379. if (hasApp.get(checkApp) > appInterference[conditionalApp].get(checkApp))
  380. throw new Exception("终态存在干扰冲突");
  381. }
  382. }
  383. }
  384. // 检查资源限制
  385. for (int i = 0; i < k; i++)
  386. if (dcmp(machineResourcesUsed[j][i] - machineResources[j][i]) > 0)
  387. throw new Exception("终态存在资源过载");
  388. // 技术得分
  389. for (int t = 0; t < T2; t++) {
  390. double usage = machineResourcesUsed[j][t] / machineResources[j][t];
  391. costs += 1. + (1. + appCnt) * (Math.exp(Math.max(0., usage - beta)) - 1.);
  392. }
  393. }
  394. costs /= T2;
  395. } catch (Exception e) {
  396. System.out.println(e.getMessage());
  397. // e.printStackTrace();
  398. costs = 1e9;
  399. }
  400. return costs;
  401. }
  402. private String toMachine(String inst, int machineIt) {
  403. return toMachine(inst, machineIt, true);
  404. }
  405. private String toMachine(String inst, int machineIt, boolean doCheck) {
  406. int appIt = inst2AppIndex.get(inst);
  407. Map<Integer, Integer> hasApp = machineHasApp[machineIt];
  408. if (doCheck) {
  409. // 检查互斥规则
  410. int nowHas = 0;
  411. if (hasApp.containsKey(appIt))
  412. nowHas = hasApp.get(appIt);
  413. for (Integer conditionalApp : hasApp.keySet()) {
  414. if (hasApp.get(conditionalApp) <= 0)
  415. continue;
  416. if (!appInterference[conditionalApp].containsKey(appIt))
  417. continue;
  418. if (nowHas + 1 > appInterference[conditionalApp].get(appIt)) {
  419. return "App Interference, inst: " + inst + ", " + apps[conditionalApp] + " -> " + apps[appIt]
  420. + ", " + (nowHas + 1) + " > " + appInterference[conditionalApp].get(appIt);
  421. }
  422. }
  423. for (Integer checkApp : hasApp.keySet()) {
  424. if (!appInterference[appIt].containsKey(checkApp))
  425. continue;
  426. if (hasApp.get(checkApp) > appInterference[appIt].get(checkApp)) {
  427. return "App Interference, inst: " + inst + ", " + apps[appIt] + " -> " + apps[checkApp] + ", "
  428. + (nowHas + 1) + " > " + appInterference[appIt].get(checkApp);
  429. }
  430. }
  431. // 检查资源限制
  432. for (int i = 0; i < k; i++)
  433. if (dcmp(machineResourcesUsed[machineIt][i] + appResources[appIt][i]
  434. - machineResources[machineIt][i]) > 0)
  435. return "Resource Limit: inst: " + inst + ", " + "machine: " + machines[machineIt] + ", app: "
  436. + apps[appIt] + ", resIter: " + i + ", " + machineResourcesUsed[machineIt][i] + " + "
  437. + appResources[appIt][i] + " > " + machineResources[machineIt][i];
  438. }
  439. // 将inst放入新的machine
  440. inst2Machine.put(inst, machineIt);
  441. if (!hasApp.containsKey(appIt))
  442. hasApp.put(appIt, 0);
  443. hasApp.put(appIt, hasApp.get(appIt) + 1);
  444. for (int i = 0; i < k; i++)
  445. machineResourcesUsed[machineIt][i] += appResources[appIt][i];
  446. return "success";
  447. }
  448. private void pickInstance(String inst, int fromMachine) throws Exception {
  449. int appIt = inst2AppIndex.get(inst);
  450. // 更新machineHasApp
  451. Map<Integer, Integer> fromHasApp = machineHasApp[fromMachine];
  452. if (!fromHasApp.containsKey(appIt))
  453. throw new Exception("[DEBUG 12] Stupid judger");
  454. fromHasApp.put(appIt, fromHasApp.get(appIt) - 1);
  455. if (fromHasApp.get(appIt) <= 0)
  456. fromHasApp.remove(appIt);
  457. // 更新machineResourcesUsed
  458. for (int i = 0; i < k; i++)
  459. machineResourcesUsed[fromMachine][i] -= appResources[appIt][i];
  460. }
  461. private int dcmp(double x) {
  462. if (Math.abs(x) < 1e-9)
  463. return 0;
  464. return x < 0. ? -1 : 1;
  465. }
  466. }
  467. }