From 111c5b61165d904be0471cc2abb9b482809c9338 Mon Sep 17 00:00:00 2001 From: HappyZ Date: Fri, 27 Jan 2017 15:46:01 -0800 Subject: [PATCH] fixed multi-core support; cleaned up some bugs --- .../sandlab/offloadingdemo/MainActivity.java | 56 +-- .../cs/sandlab/offloadingdemo/SSLogger.java | 15 +- .../cs/sandlab/offloadingdemo/Utilities.java | 324 +++++++++++------- 3 files changed, 235 insertions(+), 160 deletions(-) diff --git a/OffloadingDemo/mobile/src/main/java/edu/ucsb/cs/sandlab/offloadingdemo/MainActivity.java b/OffloadingDemo/mobile/src/main/java/edu/ucsb/cs/sandlab/offloadingdemo/MainActivity.java index 86e9879..b42a461 100755 --- a/OffloadingDemo/mobile/src/main/java/edu/ucsb/cs/sandlab/offloadingdemo/MainActivity.java +++ b/OffloadingDemo/mobile/src/main/java/edu/ucsb/cs/sandlab/offloadingdemo/MainActivity.java @@ -40,7 +40,6 @@ public class MainActivity extends Activity { protected static final String udpserver_pathport = "~/mobileRDMABeach/UDPServer 32000 "; protected static final String binaryFolderPath = "/data/local/tmp/"; protected static final String binary_tcpdump = "tcpdump"; - protected static final int oneMB = 1048576; private static final String TAG = "MainActivity"; private static final int mVersion = Build.VERSION.SDK_INT; // the configs @@ -66,7 +65,7 @@ public class MainActivity extends Activity { protected static int UDPfinishTime = 0; protected static double reportedFinishTime = 0.0; protected static int repeatCounts = 3; - protected static int bytes2send = 10 * oneMB; // default 10MB + protected static int bytes2send = 10 * Utilities.oneMB; // default 10MB protected static int currentBandwidth = -1; // bps, default is -1, indicating unlimited protected static TextView txt_results; protected static Handler myHandler; @@ -550,9 +549,10 @@ public class MainActivity extends Activity { } /** - * Intialize parameters etc. + * Initialize parameters etc. */ protected void initialization() { + // must have root privilege in order to run try { Runtime.getRuntime().exec("su"); @@ -561,12 +561,26 @@ public class MainActivity extends Activity { } catch (Throwable e) { Toast.makeText(this, R.string.warn_root, Toast.LENGTH_LONG).show(); } + // must have storage permission Utilities.verifyStoragePermissions(this); + + // permission error + if (!Utilities.canWriteOnExternalStorage()) { + Log.d(TAG, "Permission error: cannot write on external storage."); + MainActivity.myHandler.post(new Runnable() { + @Override + public void run() { + MainActivity.txt_results.append("Can't write on external storage!\n"); + } + }); + } + // handler that updates the ui at main thread // it's used in sslogger thus will be modded in receiver activity also // do not modify this myHandler = new Handler(); + // sslogger intent intentSSLogger = new Intent(this, SSLogger.class); // grab WiFi service and check if wifi is enabled @@ -638,39 +652,39 @@ public class MainActivity extends Activity { @Override public void onClick(View v) { final CharSequence[] mItems={ - (bytes2send == (oneMB/2))?"Current: 0.5MB":"0.5MB", - (bytes2send == (oneMB))?"Current: 1MB":"1MB", - (bytes2send == (2*oneMB))?"Current: 2MB":"2MB", - (bytes2send == (5*oneMB))?"Current: 5MB":"5MB", - (bytes2send == (10*oneMB))?"Current: 10MB":"10MB", - (bytes2send == (20*oneMB))?"Current: 20MB":"20MB", - (bytes2send == (50*oneMB))?"Current: 50MB":"50MB", - (bytes2send == (100*oneMB))?"Current: 100MB":"100MB", - (bytes2send == (200*oneMB))?"Current: 200MB":"200MB", - (bytes2send == (500*oneMB))?"Current: 500MB":"500MB", - (bytes2send == (1000*oneMB))?"Current: 1GB":"1GB"}; + (bytes2send == (Utilities.oneMB/2))?"Current: 0.5MB":"0.5MB", + (bytes2send == (Utilities.oneMB))?"Current: 1MB":"1MB", + (bytes2send == (2*Utilities.oneMB))?"Current: 2MB":"2MB", + (bytes2send == (5*Utilities.oneMB))?"Current: 5MB":"5MB", + (bytes2send == (10*Utilities.oneMB))?"Current: 10MB":"10MB", + (bytes2send == (20*Utilities.oneMB))?"Current: 20MB":"20MB", + (bytes2send == (50*Utilities.oneMB))?"Current: 50MB":"50MB", + (bytes2send == (100*Utilities.oneMB))?"Current: 100MB":"100MB", + (bytes2send == (200*Utilities.oneMB))?"Current: 200MB":"200MB", + (bytes2send == (500*Utilities.oneMB))?"Current: 500MB":"500MB", + (bytes2send == (1000*Utilities.oneMB))?"Current: 1GB":"1GB"}; AlertDialog.Builder mDialog = new AlertDialog.Builder(MainActivity.this); mDialog.setItems(mItems, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (which < 3) { - bytes2send = oneMB/2; + bytes2send = Utilities.oneMB/2; for (int i = 0; i < which; ++i) bytes2send *= 2; } else if (which < 6) { - bytes2send = 5 * oneMB; + bytes2send = 5 * Utilities.oneMB; for (int i = 3; i < which; ++i) bytes2send *= 2; } else if (which < 9) { - bytes2send = 50 * oneMB; + bytes2send = 50 * Utilities.oneMB; for (int i = 6; i < which; ++i) bytes2send *= 2; } else if (which == 9) { - bytes2send = 500 * oneMB; + bytes2send = 500 * Utilities.oneMB; } else if (which == 10) { - bytes2send = 1000 * oneMB; + bytes2send = 1000 * Utilities.oneMB; } else { - bytes2send = 10 * oneMB; // default 10MB + bytes2send = 10 * Utilities.oneMB; // default 10MB } if (isVerbose) { Log.d(TAG, "outgoing/incoming bytes is set to " + bytes2send); @@ -716,7 +730,7 @@ public class MainActivity extends Activity { out.add("Disable TCPDump"); } try { - Process proc = Runtime.getRuntime().exec("ls /sys/class/net"); + Process proc = Runtime.getRuntime().exec("su -c ls /sys/class/net"); proc.waitFor(); String line; BufferedReader is = new BufferedReader(new InputStreamReader(proc.getInputStream())); diff --git a/OffloadingDemo/mobile/src/main/java/edu/ucsb/cs/sandlab/offloadingdemo/SSLogger.java b/OffloadingDemo/mobile/src/main/java/edu/ucsb/cs/sandlab/offloadingdemo/SSLogger.java index b0bb4ca..cd86671 100755 --- a/OffloadingDemo/mobile/src/main/java/edu/ucsb/cs/sandlab/offloadingdemo/SSLogger.java +++ b/OffloadingDemo/mobile/src/main/java/edu/ucsb/cs/sandlab/offloadingdemo/SSLogger.java @@ -57,13 +57,6 @@ public class SSLogger extends Service { String[] cpuUsage = new String[MainActivity.coreNum + 1]; // placeholder for each core String[] cpuFreq = new String[MainActivity.coreNum]; // placeholder for each core - // first line to write is instruction - tmp = "# timestamp totalUsage"; - for (i = 0; i < MainActivity.coreNum; ++i) { - tmp += " cpu" + i + " freq" + i; - } - tmp += "\n"; - // if SSLogger is set to run while(isRunning) { @@ -77,7 +70,7 @@ public class SSLogger extends Service { readFrequency(cpuFreq); // construct bytes for cpuRaw log - tmp += mTime + " " + cpuUsage[0]; + tmp = mTime + " " + cpuUsage[0]; for (i = 0; i < MainActivity.coreNum; ++i) { tmp += " " + cpuUsage[i + 1] + " " + cpuFreq[i]; } @@ -186,12 +179,6 @@ public class SSLogger extends Service { // permission error if (!Utilities.canWriteOnExternalStorage()) { - MainActivity.myHandler.post(new Runnable() { - @Override - public void run() { - MainActivity.txt_results.append("Can't write sdcard\n"); - } - }); onDestroy(); } diff --git a/OffloadingDemo/mobile/src/main/java/edu/ucsb/cs/sandlab/offloadingdemo/Utilities.java b/OffloadingDemo/mobile/src/main/java/edu/ucsb/cs/sandlab/offloadingdemo/Utilities.java index 86108e9..b1f32eb 100755 --- a/OffloadingDemo/mobile/src/main/java/edu/ucsb/cs/sandlab/offloadingdemo/Utilities.java +++ b/OffloadingDemo/mobile/src/main/java/edu/ucsb/cs/sandlab/offloadingdemo/Utilities.java @@ -24,6 +24,7 @@ import java.util.Collections; import java.util.Date; import java.util.Enumeration; import java.util.List; +import java.util.Locale; /** * Created by yanzi on 10/1/15. @@ -33,8 +34,9 @@ public class Utilities { private static final String TAG = "Utilities"; // variables - protected static String myInetIP = "127.0.0.1"; - protected static String myMAC = ""; + static int oneMB = 1048576; + static String myInetIP = null; + static String myMAC = null; // Storage Permissions private static final int REQUEST_EXTERNAL_STORAGE = 1; @@ -43,13 +45,15 @@ public class Utilities { Manifest.permission.WRITE_EXTERNAL_STORAGE }; + + /** * Android 6.0 + required * Checks if the app has permission to write to device storage * If the app does not has permission then the user will be prompted to grant permissions - * @param activity + * @param activity: */ - public static void verifyStoragePermissions(Activity activity) { + static void verifyStoragePermissions(Activity activity) { // Check if we have write permission int permission = ActivityCompat.checkSelfPermission( activity, Manifest.permission.WRITE_EXTERNAL_STORAGE); @@ -69,7 +73,7 @@ public class Utilities { * check if we can write on external storage * @return true/false */ - public static boolean canWriteOnExternalStorage() { + static boolean canWriteOnExternalStorage() { String state = Environment.getExternalStorageState(); if (Environment.MEDIA_MOUNTED.equals(state)) { return true; @@ -80,11 +84,13 @@ public class Utilities { /** * get the ip and mac addresses */ - protected static void getSelfIdentity(String interface_name, boolean useIPv4) { + static void getSelfIdentity(String interface_name, boolean useIPv4) { String name; Enumeration networks; Enumeration inetAddresses; NetworkInterface network; + myInetIP = null; + myMAC = null; try { networks = NetworkInterface.getNetworkInterfaces(); @@ -109,7 +115,6 @@ public class Utilities { } myMAC = sb.toString(); } - Log.d(TAG, "myMAC: " + myMAC); // get the ip address inetAddresses = network.getInetAddresses(); @@ -132,21 +137,32 @@ public class Utilities { } } } - Log.d(TAG, "myIP: " + myInetIP); } } catch (SocketException e) { e.printStackTrace(); } + if (myMAC == null) { + Log.d(TAG, "Failed to get MAC from interface " + interface_name); + myMAC = "00:00:00:00:00:00"; + } + + if (myInetIP == null) { + Log.d(TAG, "Failed to get IP from interface " + interface_name); + myInetIP = "127.0.0.1"; + } + + Log.d(TAG, "myMAC: " + myMAC); + Log.d(TAG, "myIP: " + myInetIP); } /** * parse binary file output - * @param output + * @param output: * @return double */ - protected static double parseBinOutput(String output) { + static double parseBinOutput(String output) { String[] toks = output.trim().split(":"); if (toks.length == 2) { return Double.parseDouble(toks[1]); @@ -158,7 +174,7 @@ public class Utilities { * get the number of cores of device * @return int > 0 */ - protected static int getNumCores() { + static int getNumCores() { Process proc; BufferedReader stdout_buf; String stdout; @@ -202,40 +218,45 @@ public class Utilities { */ protected static int getMyPID(String inName, boolean flag) { String commd; + Process proc; + BufferedReader stdout_buf; + String stdout; + + // get commd ready if (flag) commd = "su -c busybox ps | grep " + inName + " | grep -v grep | head -1 | awk '{print $1}'"; else commd = "su -c busybox ps | grep " + inName + " | grep -v grep | head -1 | awk '{print $3}'"; + try { - Process proc = Runtime.getRuntime().exec(commd); + proc = Runtime.getRuntime().exec(commd); proc.waitFor(); - String line; - StringBuilder out = new StringBuilder(); - BufferedReader is = new BufferedReader( - new InputStreamReader(proc.getInputStream())); - while ((line = is.readLine()) != null) { - out.append(line).append("\n"); + + // read std out + stdout_buf = new BufferedReader(new InputStreamReader( + proc.getInputStream())); + + stdout = stdout_buf.readLine(); + stdout_buf.close(); + + if (! stdout.equals("")) { + Log.d(TAG, inName + "PID: " + stdout); + return Integer.parseInt(stdout); } - String tmp = out.toString().trim(); - if (!tmp.equals("")) { - return Integer.parseInt(tmp); - } - } catch (InterruptedException unimportant) { - Log.d(TAG, "InterruptedException but unimportant"); - } catch (IOException e) { - Log.d(TAG, "IOException but unimportant"); + } catch (InterruptedException | IOException ignored) { + Log.d(TAG, "Faild to fetch PID for " + inName); } return -1; } /** * check if a file exists - * @param myFile + * @param myFile: * @return true/false */ - protected static boolean fileExist(String myFile) { + static boolean fileExist(String myFile) { File file = new File(myFile); if (file.exists() && file.isFile()) return true; @@ -244,11 +265,11 @@ public class Utilities { /** * check if a directory exists - * @param myDirectory + * @param myDirectory: * @param createIfNot: try to create the folder if directory does not exist * @return true/false */ - protected static boolean dirExist(String myDirectory, boolean createIfNot) { + static boolean dirExist(String myDirectory, boolean createIfNot) { File file = new File(myDirectory); if (file.exists() && file.isDirectory()) return true; @@ -264,116 +285,154 @@ public class Utilities { } /** - * parse CPU for a folder - * @param folderName + * post parse CPU for a folder + * @param folderName: * @return true/false */ - protected static boolean parseCPUforFolder(String folderName) { + static boolean parseCPUforFolder(String folderName) { + Process proc; + BufferedReader stdout_buf, br; + FileOutputStream os_cpu; + String cpuFile, line, tmp; + int i, offset; + try { - Process proc = Runtime.getRuntime().exec( + proc = Runtime.getRuntime().exec( "su && cd " + MainActivity.outFolderPath + "/" + folderName + " && ls *.cpuRaw"); proc.waitFor(); - InputStream stdout = proc.getInputStream(); - byte[] buffer = new byte[20]; - int read; - StringBuilder out = new StringBuilder(); - while(true){ - read = stdout.read(buffer); - if(read<0){ - Log.d(TAG, "Failed in parseCPUforFolder: ls nothing"); - break; - } - out.append(new String(buffer, 0, read)); - if(read<20){ - break; - } - } - if (!out.toString().equals("")) { - String[] cpuFiles = out.toString().split("\\n"); - for (int i = 0; i < cpuFiles.length; ++i) { - try { - BufferedReader br = new BufferedReader( - new FileReader( - MainActivity.outFolderPath + "/" - + folderName + "/" + cpuFiles[i])); - FileOutputStream os_cpu = new FileOutputStream( - new File( - MainActivity.outFolderPath + "/" - + folderName, - cpuFiles[i].replace("cpuRaw", "cpu"))); - String line; - while ((line = br.readLine()) != null) { - String[] toks = line.split("\\s+"); - // format for Ana's script: - // time - // cpuTotal idle - // cpuTotal used - // cpu0 idle - // cpu0 used - // cpu0 freq - // cpu1 freq - // cpuTotal normal process user mode - // cpuTotal niced process in user mode - // cpuTotal kernal mode - // cpuTotal IO - // cpuTotal hardware interrupts - // cpuTotal software interrupts - // cpu0 normal process user mode - // cpu0 niced process in user mode - // cpu0 kernal mode - // cpu0 IO - // cpu0 hardware interrupts - // cpu0 software interrupts - os_cpu.write((toks[0] + " " // time - // cpuTotal toks[1-11] - + toks[5] + " " // cpuTotal idle - // cpuTotal used - + (Long.parseLong(toks[2]) + Long.parseLong(toks[3]) - + Long.parseLong(toks[4]) + Long.parseLong(toks[6]) - + Long.parseLong(toks[7]) + Long.parseLong(toks[8])) + " " - // cpu 0 toks[12-22] - + toks[16] + " " // cpu0 idle - // cpu0 used - + (Long.parseLong(toks[13]) + Long.parseLong(toks[14]) - + Long.parseLong(toks[15]) + Long.parseLong(toks[17]) - + Long.parseLong(toks[18]) + Long.parseLong(toks[19])) + " " - // cpu 0 freq toks[23] - + toks[23] + " " - // cpu 1 freq toks[35] - + toks[35] + " " - // cpuTotal details - + toks[2] + " " + toks[3] + " " + toks[4] + " " - + toks[6] + " " + toks[7] + " " + toks[8] + " " - // cpu0 details - + toks[13] + " " + toks[14] + " " + toks[15] + " " - + toks[17] + " " + toks[18] + " " + toks[19]).getBytes()); - // cpu 1 toks[24-34] - os_cpu.write("\n".getBytes()); - os_cpu.flush(); - } - os_cpu.close(); - } catch (IOException unimportant) { - return false; + + // read std out + stdout_buf = new BufferedReader(new InputStreamReader( + proc.getInputStream())); + + while ((cpuFile = stdout_buf.readLine()) != null) { + br = new BufferedReader(new FileReader( + MainActivity.outFolderPath + "/" + + folderName + "/" + cpuFile)); + + os_cpu = new FileOutputStream(new File( + MainActivity.outFolderPath + "/" + + folderName + "/" + cpuFile.replace("cpuRaw", "cpu"))); + + while ((line = br.readLine()) != null) { + + String[] s = line.split("\\s+"); + + /* + * each line format as the following + * [ // 0 1 2 3 4 5 6 7 8 9-11 + * timestamp, "cpu", user, nice, system, idle, iowait, irq, softirq, 0, 0, 0, + * // 12 13 14 15 16 17 18 19 20-22 23 + * "cpu0", user, nice, system, idle, iowait, irq, softirq, 0, 0, 0, frequency, + * ... + * ] + */ + + tmp = s[0] + " " // timestamp + + s[5] + " " // cpu_total idle + + parseUsedCPU(s, 1); // cpu_total used + + for (i = 0; i < MainActivity.coreNum; ++i) { + offset = (i + 1) * 12; + tmp += " " + s[4 + offset] // cpu_i idle + + " " + parseUsedCPU(s, offset) // cpu_i used + + " " + s[offset + 11]; // cpu_i frequency } + tmp += "\n"; + + /* + * convert to parsed format (each line): + * [ + * timestamp, cpu_total idle, cpu_total used, + * cpu_0 idle, cpu_0 used, cpu_0 frequency, + * ... + * ] + */ + os_cpu.write(tmp.getBytes()); + + + // format for Ana's script: + // time + // cpuTotal idle + // cpuTotal used + // cpu0 idle + // cpu0 used + // cpu0 freq + // cpu1 freq + // cpuTotal normal process user mode + // cpuTotal niced process in user mode + // cpuTotal kernal mode + // cpuTotal IO + // cpuTotal hardware interrupts + // cpuTotal software interrupts + // cpu0 normal process user mode + // cpu0 niced process in user mode + // cpu0 kernal mode + // cpu0 IO + // cpu0 hardware interrupts + // cpu0 software interrupts +// os_cpu.write((toks[0] + " " // time +// // cpuTotal toks[1-11] +// + toks[5] + " " // cpuTotal idle +// // cpuTotal used +// + (Long.parseLong(toks[2]) + Long.parseLong(toks[3]) +// + Long.parseLong(toks[4]) + Long.parseLong(toks[6]) +// + Long.parseLong(toks[7]) + Long.parseLong(toks[8])) + " " +// // cpu 0 toks[12-22] +// + toks[16] + " " // cpu0 idle +// // cpu0 used +// + (Long.parseLong(toks[13]) + Long.parseLong(toks[14]) +// + Long.parseLong(toks[15]) + Long.parseLong(toks[17]) +// + Long.parseLong(toks[18]) + Long.parseLong(toks[19])) + " " +// // cpu 0 freq toks[23] +// + toks[23] + " " +// // cpu 1 freq toks[35] +// + toks[35] + " " +// // cpuTotal details +// + toks[2] + " " + toks[3] + " " + toks[4] + " " +// + toks[6] + " " + toks[7] + " " + toks[8] + " " +// // cpu0 details +// + toks[13] + " " + toks[14] + " " + toks[15] + " " +// + toks[17] + " " + toks[18] + " " + toks[19]).getBytes()); +// // cpu 1 toks[24-34] +// os_cpu.write("\n".getBytes()); } + + br.close(); + os_cpu.close(); } - } catch (IOException e) { -// e.printStackTrace(); - return false; - } catch (InterruptedException e) { -// e.printStackTrace(); + + stdout_buf.close(); + + } catch (IOException | InterruptedException ignore) { return false; } return true; } + + /** + * parse the cpu usage (used) + * @param tmp: cpu usage + * @return long: used cpu usage + */ + static Long parseUsedCPU(String[] tmp, int offset) { + return (Long.parseLong(tmp[1 + offset]) + + Long.parseLong(tmp[2 + offset]) + + Long.parseLong(tmp[3 + offset]) + + Long.parseLong(tmp[5 + offset]) + + Long.parseLong(tmp[6 + offset]) + + Long.parseLong(tmp[7 + offset])); + } + + /** * Translate the selection index into throughput setup - * @param myI - * @return + * @param myI: + * @return integer */ - protected static int findCorrespondingThrpt(int myI) { + static int findCorrespondingThrpt(int myI) { if (myI < 19) { return (800 - (myI * 40)) * 1000000; } else if (myI < 37) { @@ -390,8 +449,18 @@ public class Utilities { } } - protected static void estimateTime(int numRepeats, int numSelectedItems, int totalBytes, ArrayList selectedItemsThrpt) { + /** + * Estimate how much time left + * @param numRepeats: + * @param numSelectedItems: + * @param totalBytes: + * @param selectedItemsThrpt: + */ + static void estimateTime( + int numRepeats, int numSelectedItems, int totalBytes, + ArrayList selectedItemsThrpt) { int time = 0; + if (MainActivity.isLocal) { for (int k = 0; k < selectedItemsThrpt.size(); ++k) time += (Math.max(totalBytes / findCorrespondingThrpt(selectedItemsThrpt.get(k)) + 20, 20)); @@ -399,8 +468,13 @@ public class Utilities { for (int k = 0; k < selectedItemsThrpt.size(); ++k) time += (Math.max(totalBytes / findCorrespondingThrpt(selectedItemsThrpt.get(k)) + 20, 60)); } + time = (time + 15) * numSelectedItems * numRepeats * 1000; - final String estimatedTime = new SimpleDateFormat("MM/dd HH:mm:ss").format(new Date(System.currentTimeMillis() + time)); + + final String estimatedTime = + new SimpleDateFormat("MM/dd HH:mm:ss", Locale.US).format( + new Date(System.currentTimeMillis() + time)); + MainActivity.myHandler.post(new Runnable() { @Override public void run() {