Main3.java 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. package me.yoqi.servermanager;
  2. import java.io.BufferedReader;
  3. import java.io.BufferedWriter;
  4. import java.io.ByteArrayInputStream;
  5. import java.io.File;
  6. import java.io.FileInputStream;
  7. import java.io.FileReader;
  8. import java.io.FileWriter;
  9. import java.io.IOException;
  10. import java.io.InputStream;
  11. import java.io.InputStreamReader;
  12. import java.util.ArrayList;
  13. import java.util.HashMap;
  14. import java.util.List;
  15. import java.util.Map;
  16. import com.google.common.base.Charsets;
  17. /**
  18. * 不考虑迁移代价而不断迁移,跑b数据9746。 Created by liuyuqi.gov@msn.cn on 2018/07/02.
  19. */
  20. public class Main3 {
  21. // 参数
  22. public static final double alpha = 10.;
  23. public static final double beta = 0.5;
  24. public static final int T = 98;
  25. public static final int EXEC_LIMIT = 100000;
  26. // 静态数据
  27. private int num_app; // app数 9338
  28. private int num_inst; // inst数 68219
  29. private int num_mac; // machine数 6000
  30. private int num_k; // 资源种类 200
  31. private List<Integer> cpuIter; // [0, 1, 2, ... 97]
  32. private Map<String, Integer> appIndex; // app_1,app_2字符串用0,1等数字替换,{app_1=0,
  33. // app_2=1,...,app_4=3}
  34. private Map<String, Integer> machineIndex;// {machine_1=0, machine_2=1,
  35. private List<Integer> machinePriorIndex = new ArrayList<Integer>();
  36. private String[] apps; // [app_1, app_2, app_3, app_4,
  37. private String[] machines;// [machine_1, machine_2, machine_3, machine_4,
  38. private Map<String, Integer> inst2AppIndex;// {inst_157=49}
  39. private double[][] appResources;// app 9338*200
  40. private double[][] machineResources;// 主机 6000*200
  41. private Map<Integer, Integer>[] appInterference;// 9338 限制条件[{}, {},
  42. // {3517=2}, {}, {5600=1,
  43. // 6747=2, 7707=2, 4830=2},
  44. // 动态数据
  45. private Map<String, Integer> inst2Machine;// 部署 {inst_33717=5456,
  46. // 这个数据类型和Map<String, Integer>有点区别,加上list会保存顺序
  47. private List<String> deployResult = new ArrayList<String>(); // [inst_33717,5456
  48. private List<String> instUnDelpoy = new ArrayList<String>();// 未部署的实例
  49. private List<String> instSortByDisk = new ArrayList<String>();// 未部署的实例
  50. private Map<String, Integer> inst2MachineDefaultConflict = new HashMap<String, Integer>();;// 记录初始部署冲突的实例和主机
  51. private double[][] machineResourcesUsed;// 6000*200
  52. private Map<Integer, Integer>[] machineHasApp;// 6000 [{}, {},{6004=1,
  53. /**
  54. * 先对disk排序,然后first fit
  55. *
  56. * @throws IOException
  57. * 写文件异常
  58. */
  59. private void run() throws IOException {
  60. // 主机优先顺序,使用过的主机在前,目的紧凑;然后大主机在前。做一个主机优先部署序列
  61. String tmp_Res;
  62. String inst_tmp = null;
  63. int time_count = 0;
  64. long startTime=System.currentTimeMillis();
  65. long cost_time = 0;
  66. for (Map.Entry<String, Integer> entry : inst2AppIndex.entrySet()) {
  67. // 判断是否部署过,如果部署过则重新部署
  68. inst_tmp = entry.getKey();
  69. if (inst2Machine.containsKey(inst_tmp)) {
  70. pickInstance(entry.getKey());
  71. }
  72. for (int i = num_mac - 1; i >= 0; i--) {
  73. tmp_Res = toMachine(inst_tmp, i);
  74. if (tmp_Res == "success") {
  75. deployResult.add(inst_tmp + "," + "machine_" + (i + 1));
  76. break;
  77. }
  78. }
  79. time_count++;
  80. if (time_count % 5000 == 0) {
  81. cost_time = System.currentTimeMillis() - startTime;
  82. System.out.println("已经部署:" + time_count+" 剩余部署:" + (num_inst - time_count));
  83. System.out.println("预估剩余时间:" + ((cost_time / 1000) * (num_inst - time_count) / time_count)+"s");
  84. }
  85. }
  86. saveResult(deployResult);
  87. }
  88. // 读取数据
  89. protected void init(BufferedReader bufferedReader) throws IOException {
  90. cpuIter = new ArrayList<Integer>();
  91. for (int i = 0; i < T; i++)
  92. cpuIter.add(i);
  93. /** Read app_resources */
  94. num_app = Integer.parseInt(bufferedReader.readLine());// 9338
  95. apps = new String[num_app];
  96. for (int i = 0; i < num_app; i++) {// 循环app表每一行
  97. // appId,resources
  98. String line = bufferedReader.readLine();
  99. String[] parts = line.split(",", -1);
  100. List<Double> resources = new ArrayList<Double>();
  101. for (String x : parts[1].split("\\|", -1))// cpu
  102. resources.add(Double.parseDouble(x));
  103. for (String x : parts[2].split("\\|", -1))// mem
  104. resources.add(Double.parseDouble(x));
  105. for (int j = 3; j < parts.length; j++) // disk/P/M/PM
  106. resources.add(Double.parseDouble(parts[j]));
  107. if (i == 0) {
  108. num_k = resources.size();
  109. appIndex = new HashMap<String, Integer>();
  110. appResources = new double[num_app][num_k];
  111. }
  112. if (num_k != resources.size())
  113. throw new IOException("[DEBUG 2]Invaild problem");
  114. if (appIndex.containsKey(parts[0]))
  115. throw new IOException("[DEBUG 3]Invaild problem");
  116. appIndex.put(parts[0], i);
  117. apps[i] = parts[0];// [app_1, app_2, app_3, app_4]
  118. for (int j = 0; j < num_k; j++)
  119. appResources[i][j] = resources.get(j);
  120. }
  121. /** Read machine_resources */
  122. num_mac = Integer.parseInt(bufferedReader.readLine());// 6000
  123. machineResources = new double[num_mac][num_k];
  124. machineResourcesUsed = new double[num_mac][num_k];
  125. machineIndex = new HashMap<String, Integer>();// {machine_3791=3790,
  126. machineHasApp = new Map[num_mac];
  127. machines = new String[num_mac];
  128. for (int i = 0; i < num_mac; i++) {
  129. // machineId,resources
  130. String line = bufferedReader.readLine();
  131. String[] parts = line.split(",", -1);
  132. if (machineIndex.containsKey(parts[0]))
  133. throw new IOException("[DEBUG 4]Invaild problem");
  134. machineIndex.put(parts[0], i);
  135. machines[i] = parts[0];
  136. machineHasApp[i] = new HashMap<Integer, Integer>();
  137. double cpu = Double.parseDouble(parts[1]);
  138. double mem = Double.parseDouble(parts[2]);
  139. for (int j = 0; j < T; j++) {
  140. machineResources[i][j] = cpu;
  141. machineResources[i][T + j] = mem;
  142. }
  143. for (int j = 3; j < parts.length; j++)
  144. machineResources[i][2 * T + j - 3] = Double.parseDouble(parts[j]);
  145. for (int j = 0; j < num_k; j++)
  146. machineResourcesUsed[i][j] = 0.;
  147. }
  148. /** Read app_interference */
  149. int icnt = Integer.parseInt(bufferedReader.readLine());// 35242
  150. appInterference = new Map[num_app];
  151. for (int i = 0; i < num_app; i++)
  152. appInterference[i] = new HashMap<Integer, Integer>();
  153. for (int i = 0; i < icnt; i++) {
  154. String line = bufferedReader.readLine();
  155. String[] parts = line.split(",", -1);
  156. if (!appIndex.containsKey(parts[0]) || !appIndex.containsKey(parts[1]))
  157. throw new IOException("[DEBUG 8]Invaild problem");
  158. int app1 = appIndex.get(parts[0]);
  159. int app2 = appIndex.get(parts[1]);
  160. int limit = Integer.parseInt(parts[2]);
  161. Map<Integer, Integer> inter = appInterference[app1];
  162. if (inter.containsKey(app2))
  163. throw new IOException("[DEBUG 9]Invaild problem");
  164. if (app1 == app2)
  165. limit += 1; // self-interference +1 here
  166. inter.put(app2, limit);
  167. }
  168. /** Read instance_deploy */
  169. num_inst = Integer.parseInt(bufferedReader.readLine());// 68219
  170. inst2AppIndex = new HashMap<String, Integer>();// 68219*2
  171. // {inst_33717=8766,
  172. // inst_33718=2956}
  173. inst2Machine = new HashMap<String, Integer>();// {inst_33717=5456,
  174. for (int i = 0; i < num_inst; i++) {
  175. String line = bufferedReader.readLine();
  176. String[] parts = line.split(",", -1);
  177. if (inst2AppIndex.containsKey(parts[0]))
  178. throw new IOException("[DEBUG 5]Invaild problem");
  179. if (!appIndex.containsKey(parts[1]))
  180. throw new IOException("[DEBUG 6]Invaild problem");
  181. inst2AppIndex.put(parts[0], appIndex.get(parts[1]));
  182. if (!"".equals(parts[2])) {
  183. if (!machineIndex.containsKey(parts[2]))
  184. throw new IOException("[DEBUG 7]Invaild problem");
  185. toMachineDefault(parts[0], machineIndex.get(parts[2]));
  186. } else {
  187. instUnDelpoy.add(parts[0]);
  188. }
  189. }
  190. System.out.println("finish init");
  191. }
  192. private String toMachineDefault(String inst, int machineIt) {
  193. int appIt = inst2AppIndex.get(inst);
  194. Map<Integer, Integer> hasApp = machineHasApp[machineIt];
  195. String res_tmp = doCheck(inst, machineIt);
  196. if (res_tmp != "success") {
  197. inst2MachineDefaultConflict.put(inst, machineIt);
  198. }
  199. // 将inst放入新的machine
  200. inst2Machine.put(inst, machineIt);
  201. if (!hasApp.containsKey(appIt))
  202. hasApp.put(appIt, 0);
  203. hasApp.put(appIt, hasApp.get(appIt) + 1);
  204. for (int i = 0; i < num_k; i++)
  205. machineResourcesUsed[machineIt][i] += appResources[appIt][i];
  206. return "success";
  207. }
  208. private String toMachine(String inst, int machineIt) {
  209. return toMachine(inst, machineIt, true);
  210. }
  211. private String doCheck(String inst, int machineIt) {
  212. int appIt = inst2AppIndex.get(inst);
  213. Map<Integer, Integer> hasApp = machineHasApp[machineIt];
  214. // 检查互斥规则,初始数据这里有冲突
  215. int nowHas = 0;
  216. if (hasApp.containsKey(appIt))
  217. nowHas = hasApp.get(appIt);
  218. for (Integer conditionalApp : hasApp.keySet()) {
  219. if (hasApp.get(conditionalApp) <= 0)
  220. continue;
  221. if (!appInterference[conditionalApp].containsKey(appIt))
  222. continue;
  223. if (nowHas + 1 > appInterference[conditionalApp].get(appIt)) {
  224. return "App Interference, inst: " + inst + ", " + apps[conditionalApp] + " -> " + apps[appIt] + ", "
  225. + (nowHas + 1) + " > " + appInterference[conditionalApp].get(appIt);
  226. }
  227. }
  228. // 初始数据这里有冲突
  229. for (Integer checkApp : hasApp.keySet()) {
  230. if (!appInterference[appIt].containsKey(checkApp))
  231. continue;
  232. if (hasApp.get(checkApp) > appInterference[appIt].get(checkApp)) {
  233. return "App Interference, inst: " + inst + ", " + apps[appIt] + " -> " + apps[checkApp] + ", "
  234. + (nowHas + 1) + " > " + appInterference[appIt].get(checkApp);
  235. }
  236. }
  237. // 检查资源限制,初始数据这里没有冲突
  238. for (int i = 0; i < num_k; i++)
  239. if (dcmp(
  240. machineResourcesUsed[machineIt][i] + appResources[appIt][i] - machineResources[machineIt][i]) > 0) {
  241. String res = "Resource Limit: inst: " + inst + ", " + "machine: " + machines[machineIt] + ", app: "
  242. + apps[appIt] + ", resIter: " + i + ", " + machineResourcesUsed[machineIt][i] + " + "
  243. + appResources[appIt][i] + " > " + machineResources[machineIt][i];
  244. // System.out.println(res);
  245. return res;
  246. }
  247. return "success";
  248. }
  249. private String toMachine(String inst, int machineIt, boolean doCheck) {
  250. int appIt = inst2AppIndex.get(inst);
  251. Map<Integer, Integer> hasApp = machineHasApp[machineIt];
  252. if (doCheck) {
  253. String res_tmp = doCheck(inst, machineIt);
  254. if (res_tmp != "success") {
  255. return res_tmp;
  256. }
  257. }
  258. // 将inst放入新的machine
  259. inst2Machine.put(inst, machineIt);
  260. if (!hasApp.containsKey(appIt))
  261. hasApp.put(appIt, 0);
  262. hasApp.put(appIt, hasApp.get(appIt) + 1);
  263. for (int i = 0; i < num_k; i++)
  264. machineResourcesUsed[machineIt][i] += appResources[appIt][i];
  265. return "success";
  266. }
  267. /**
  268. * 把实例inst 移除主机,撤销消耗资源
  269. *
  270. * @param inst
  271. * 实例id
  272. */
  273. private void pickInstance(String inst) {
  274. if (!inst2Machine.containsKey(inst))
  275. return;
  276. int appIt = inst2AppIndex.get(inst);
  277. int fromMachine = inst2Machine.get(inst);
  278. // 更新machineHasApp
  279. Map<Integer, Integer> fromHasApp = machineHasApp[fromMachine];
  280. fromHasApp.put(appIt, fromHasApp.get(appIt) - 1);
  281. if (fromHasApp.get(appIt) <= 0)
  282. fromHasApp.remove(appIt);
  283. // 更新machineResourcesUsed
  284. for (int i = 0; i < num_k; i++)
  285. machineResourcesUsed[fromMachine][i] -= appResources[appIt][i];
  286. // 更新inst2Machine
  287. inst2Machine.remove(inst);
  288. }
  289. private int dcmp(double x) {
  290. if (Math.abs(x) < 1e-9)
  291. return 0;
  292. return x < 0. ? -1 : 1;
  293. }
  294. private void saveResult(List<String> res) throws IOException {
  295. String res_path = "result.csv";
  296. File file = new File(res_path);
  297. if (!file.exists()) {
  298. file.createNewFile();
  299. }
  300. BufferedWriter writer = new BufferedWriter(new FileWriter(file));
  301. for (int i = 0; i < res.size(); i++) {
  302. writer.write(res.get(i));
  303. writer.newLine();
  304. }
  305. writer.close();
  306. }
  307. public static void main(String[] args) throws Exception {
  308. if (args.length != 4 && args.length != 2) {
  309. System.err.println(
  310. "传入参数有误,使用方式为:java -cp xxx.jar app_resources.csv machine_resources.csv instance_deploy.csv app_interference.csv");
  311. return;
  312. }
  313. System.out.println("-------开始部署啦--------");
  314. long startTime = System.currentTimeMillis(); // 获取开始时间
  315. InputStream problem;
  316. // app_resources.csv
  317. // machine_resources.csv
  318. // instance_deploy.csv
  319. // app_interference.csv
  320. if (args.length == 4) {
  321. // 将赛题拼成评测数据
  322. StringBuffer sb = new StringBuffer();
  323. for (int i = 0; i < 4; i++) {
  324. List<String> lines = new ArrayList<String>();
  325. BufferedReader bs = new BufferedReader(new FileReader(new File(args[i])));
  326. for (String line = bs.readLine(); line != null; line = bs.readLine())
  327. lines.add(line);
  328. sb.append("" + lines.size()).append("\n");
  329. for (String line : lines)
  330. sb.append(line).append("\n");
  331. }
  332. String alldata = sb.toString();
  333. problem = new ByteArrayInputStream(alldata.getBytes());
  334. } else {
  335. problem = new FileInputStream(args[0]);
  336. }
  337. // 评测
  338. Main3 evaluator = new Main3();
  339. evaluator.init(new BufferedReader(new InputStreamReader(problem, Charsets.UTF_8)));
  340. System.out.println("默认已经部署了:" + evaluator.inst2Machine.size());
  341. evaluator.run();
  342. long endTime = System.currentTimeMillis(); // 获取结束时间
  343. System.out.println("程序运行时间:" + (endTime - startTime) / 1000 + "s"); // 输出程序运行时间
  344. System.out.println("-------部署结束啦--------");
  345. }
  346. }