def save_data(self, start_end_times): """ Calculates the actual request rate and prints as the first line. Saves the CDFs of latency and bandwidth betweeen 1-2 minutes to disk. Assumes that all redis client hosts report correct times. """ # Save the CDF of the start times. TODO: Debug. with open('data/distr_redis_raw_start_time_cdf.txt', 'w') as f: start_time_list = [t for (t, _, _) in start_end_times] for (t, p) in util.make_cdf_table(start_time_list): print >> f, '%.5f' % t, p # Save the start end times list. TODO: Debug. with open('data/distr_redis_raw_start_end_times.txt','w') as f: for (start_time, end_time, data_file) in start_end_times: print >> f, '%.5f' % start_time, end_time, data_file # Filter out irrelevant time values. Focus on 60th-120th seconds. min_time = min([start_time for (start_time, _, _) in start_end_times]) def is_steady_state(start_end_time_tuple): (start_time, _, _) = start_end_time_tuple return min_time + 60 <= start_time <= min_time + 120 filtered_times = filter(is_steady_state, start_end_times) filtered_times.sort() print 'Raw data size:', len(start_end_times), print 'Data between 60-120th seconds:', len(filtered_times) # Figure out the actual gaps in milliseconds. start_time_list = [start for (start, _, _) in filtered_times] gap_list = [] for index in range(0, len(start_time_list) - 1): gap = start_time_list[index + 1] - start_time_list[index] gap_list.append(gap * 1000.0) gap_list.sort() print 'Client gap: (mean, stdev) =', util.get_mean_and_stdev(gap_list), print 'median =', gap_list[len(gap_list)/2] # Calculate latency and bandwidth. latency_list = [] bandwidth_list = [] for (start_time, end_time, _) in filtered_times: if end_time is None: latency = -1 bandwidth = 0 else: latency = end_time - start_time # seconds bandwidth = DATA_LENGTH / latency # Bytes/s latency_list.append(latency * 1000.0) # milliseconds bandwidth_list.append(bandwidth * 8.0 / 1000000.0) # Mbps # Write to file. with open('data/distr_redis_latency.txt', 'w') as f: for (v, p) in util.make_cdf_table(latency_list): print >> f, v, p with open('data/distr_redis_bw.txt', 'w') as f: for (v, p) in util.make_cdf_table(bandwidth_list): print >> f, v, p
def data_analysis(): start_end_times = [] for path in os.listdir('.'): if path.startswith('simplified-') and path.endswith('.tmp'): with open(path) as f: start_end_times += pickle.load(f) print 'Loaded', path # Extract steady state. min_time = min([start_time for (start_time, _) in start_end_times]) def is_steady_state(start_end_time_tuple): (start_time, _) = start_end_time_tuple return min_time + INTERESTING_TIME_START <= start_time <= min_time + INTERESTING_TIME_END filtered_times = filter(is_steady_state, start_end_times) filtered_times.sort() print 'Raw data size:', len(start_end_times), print 'Data at steady state:', len(filtered_times) # Figure out the actual gaps in milliseconds. start_time_list = [start for (start, _) in filtered_times] gap_list = [] for index in range(0, len(start_time_list) - 1): gap = start_time_list[index + 1] - start_time_list[index] gap_list.append(gap * 1000.0) gap_list.sort() print 'Client gap: (mean, stdev) =', util.get_mean_and_stdev(gap_list), print 'median =', gap_list[len(gap_list) / 2] # Calculate latency and bandwidth. latency_list = [] bandwidth_list = [] for (start_time, end_time) in filtered_times: if end_time is None: latency = -1 bandwidth = 0 else: latency = end_time - start_time # seconds bandwidth = DATA_LENGTH / latency # Bytes/s latency_list.append(latency * 1000.0) # milliseconds bandwidth_list.append(bandwidth * 8.0 / 1000000.0) # Mbps # Write to file. with open('data/simplified_redis_latency.csv', 'w') as f: for (v, p) in util.make_cdf_table(latency_list): print >> f, '%.10f,%.10f' % (v, p) with open('data/simplified_redis_bw.csv', 'w') as f: for (v, p) in util.make_cdf_table(bandwidth_list): print >> f, '%.10f,%.10f' % (v, p)
def start_processes(process_count, worker_thread_per_process, client_count, gap_ms, data_length, redis_host): switch = Switch(config.active_config) data_length = int(data_length) total_workers = process_count * worker_thread_per_process redis_set(data_length) worker_status_queue = Queue(maxsize=total_workers) client_id_queue = Queue(maxsize=client_count) result_queue = Queue(maxsize=client_count) # Starts the worker processes that spawn individual worker threads. for _ in range(process_count): p = Process(target=RedisClientProcess, args=(worker_thread_per_process, data_length, redis_host, worker_status_queue, client_id_queue, result_queue)) p.daemon = True p.start() # Wait for all worker threads to start. while True: started_count = worker_status_queue.qsize() if started_count < total_workers: print total_workers - started_count, 'workers yet to start.' time.sleep(1) else: break # Send requests in a different thread. util.ping_test(dest_host=redis_host, how_many_pings=2) def requests(): for client_id in range(client_count): client_id_queue.put(client_id) time.sleep(gap_ms / 1000.0) t = threading.Thread(target=requests) t.daemon = True t.start() # Monitor the changes for the first minute. base_time = time.time() while True: current_count = result_queue.qsize() remaining_count = client_count - current_count print 'Current:', current_count, 'Remaining:', remaining_count if remaining_count > 0 and time.time() - base_time < 120: try: time.sleep(10) except KeyboardInterrupt: break if redis_host == REDIS_HOST_OF: rule_list = switch.dump_tables(filter_str='') print 't =', time.time() - base_time, print '; tcam_size =', len([rule for rule in rule_list if 'table_id=0' in rule]), print '; table_1_size =', len([rule for rule in rule_list if 'table_id=1' in rule]), print '; table_2_size =', len([rule for rule in rule_list if 'table_id=2' in rule]), print '; total_size =', len([rule for rule in rule_list if 'cookie' in rule]) else: break # Extract the result into local lists. All time values are expressed in ms. # We're only interested in results between 30-60 seconds. print 'Analyzing the result...' start_time_list = [] completion_time_list = [] while not result_queue.empty(): (_, start_time, end_time) = result_queue.get() if start_time - base_time >= 60: start_time_list.append(start_time * 1000.0) if end_time is None: completion_time = -100.0 # Not to be plotted. else: completion_time = (end_time - start_time) * 1000.0 completion_time_list.append(completion_time) # Calculate the actual request gap. start_time_list.sort() gap_list = [] for index in range(0, len(start_time_list) - 1): gap_list.append(start_time_list[index + 1] - start_time_list[index]) print 'Client gap: (mean, stdev) =', util.get_mean_and_stdev(gap_list) # Calculate the CDF of completion times. cdf_list = util.make_cdf(completion_time_list) with open('data/realistic_redis_completion_times.txt', 'w') as f: for (x, y) in zip(completion_time_list, cdf_list): print >> f, x, y
def data_analysis(): start_end_times = [] # Load experiment data file try: data_file = 'async-' + os.environ['EXP_NAME'] except KeyError: data_file = None for path in os.listdir('data'): if (path == data_file) or \ (data_file is None and path.startswith('async-') and path.endswith('.tmp')): with open('data/' + path) as f: start_end_times += pickle.load(f) print 'Loaded', path # Extract steady state. min_time = min([start_time for (start_time, _) in start_end_times]) def is_steady_state(start_end_time_tuple): (start_time, _) = start_end_time_tuple return min_time + INTERESTING_TIME_START <= start_time <= min_time + INTERESTING_TIME_END filtered_times = filter(is_steady_state, start_end_times) filtered_times.sort() print 'Raw data size:', len(start_end_times), print 'Data at steady state:', len(filtered_times) # Figure out the actual gaps in milliseconds. start_time_list = [start for (start, _) in filtered_times] gap_list = [] for index in range(0, len(start_time_list) - 1): gap = start_time_list[index + 1] - start_time_list[index] gap_list.append(gap * 1000.0) gap_list.sort() print 'Client gap: (mean, stdev) =', util.get_mean_and_stdev(gap_list), print 'median =', gap_list[len(gap_list)/2] # Save start_time list and gap list. with open('data/start_times.csv', 'w') as start_time_f: for start_time_v in start_time_list: print >> start_time_f, '%.8f' % start_time_v with open('data/gaps.csv', 'w') as gap_f: for (v, p) in util.make_cdf_table(gap_list): print >> gap_f, '%f,%f' % (v, p) # Calculate latency and bandwidth. latency_list = [] bandwidth_list = [] for (start_time, end_time) in filtered_times: if end_time is None: latency = 1000 bandwidth = 0 else: latency = end_time - start_time # seconds bandwidth = DATA_LENGTH / latency # Bytes/s latency_list.append(latency * 1000.0) # milliseconds bandwidth_list.append(bandwidth * 8.0 / 1000000.0) # Mbps # Write to file. print 'Writing to data/async_redis_latency.csv...' with open('data/async_redis_latency.csv', 'w') as f: for (v, p) in util.make_cdf_table(latency_list): print >> f, '%.10f,%.10f' % (v, p) print 'Writing to data/async_redis_bw.csv...' with open('data/async_redis_bw.csv', 'w') as f: for (v, p) in util.make_cdf_table(bandwidth_list): print >> f, '%.10f,%.10f' % (v, p) # Analyze timings of OF events. subprocess.call('cp of_timings.csv data/; cp /tmp/client.pcap /tmp/server.pcap data/', shell=True) import timing_analysis timing_analysis.main('data/client.pcap', 'data/of_timings.csv', 'data/server.pcap')
def run(packet_per_second=100, pkt_size=1500, run_time=220): """ Returns (pktgen_pps, pkt_in_pps, flow_mod_pps, flow_mod_pps_stdev, pkt_out_pps), where pps_in is the actual number of packets/sec of pktgen, and flow_mod_pps and flow_mod_pps_stdev are the mean and stdev pps of successful flow installations at steady state. """ util.ping_test() switch = Switch(config.active_config) switch.reset_flow_table() # Initialize the experimental controller so that POX would have the # necessary settings. control_client = ExpControlClient('mumu.ucsd.edu') control_client.execute(['RESET']) control_client.execute(['SET', 'flow_stat_interval', 20]) control_client.execute(['SET', 'install_bogus_rules', True]) control_client.execute(['SET', 'emulate_hp_switch', True]) # Start capturing packets. tcpdump = Tcpdump(config.active_config) tcpdump.start() tcpdump_start_time = time.time() # Start firing packets. pktgen = Pktgen(config.active_config) gap = 1.0 / packet_per_second pkt_count = int(run_time * packet_per_second) pktgen.low_level_start(pkt_count=pkt_count, pkt_size=pkt_size, gap_ns=gap*1000*1000*1000, flow_count=1) pktgen_start_time = time.time() flow_mod_pps_list = [] # How fast were rules successfully written into the hardware table? We take # statistics at steady state. Also display flow statistics once in a while. last_stat_time = [0] def callback(t_left): flow_stat_dict = control_client.execute(['GET', 'flow_count_dict']) for stat_time in sorted(flow_stat_dict.keys()): if stat_time > last_stat_time[0]: last_stat_time[0] = stat_time flow_count = flow_stat_dict[stat_time] print t_left, 'seconds left, with flows', flow_count if pktgen_start_time + 60 <= time.time() <= pktgen_start_time + 180: flow_mod_pps_list.append(flow_count / 10.0) # Check the stat every 20 seconds. util.callback_sleep(run_time, callback, interval=20) # How fast were packets actually generated? pktgen_result = pktgen.stop_and_get_result() pktgen_pps = pktgen_result.sent_pkt_count / pktgen_result.running_time # How fast were pkt_out events? tcpdump_end_time = time.time() tcpdump_result = tcpdump.stop_and_get_result() pkt_out_pps = (tcpdump_result.dropped_pkt_count + tcpdump_result.recvd_pkt_count) / \ (tcpdump_end_time - tcpdump_start_time) # Calculate the mean and stdev of successful flow_mod pps. (flow_mod_pps, flow_mod_pps_stdev) = util.get_mean_and_stdev(flow_mod_pps_list) # How fast were pkt_in events arriving? pkt_in_count = control_client.execute(['GET', 'pkt_in_count']) pkt_in_start_time = control_client.execute(['GET', 'pkt_in_start_time']) pkt_in_end_time = control_client.execute(['GET', 'pkt_in_end_time']) pkt_in_pps = pkt_in_count / (pkt_in_end_time - pkt_in_start_time) return (pktgen_pps, pkt_in_pps, flow_mod_pps, flow_mod_pps_stdev, pkt_out_pps)