/****************************************************************************** * tools/xenbaked.c * * Tool for collecting raw trace buffer data from Xen and * performing some accumulation operations and other processing * on it. * * Copyright (C) 2004 by Intel Research Cambridge * Copyright (C) 2005 by Hewlett Packard, Palo Alto and Fort Collins * Copyright (C) 2006 by Hewlett Packard Fort Collins * * Authors: Diwaker Gupta, diwaker.gupta@hp.com * Rob Gardner, rob.gardner@hp.com * Lucy Cherkasova, lucy.cherkasova.hp.com * Much code based on xentrace, authored by Mark Williamson, * mark.a.williamson@intel.com * Date: November, 2005 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; under version 2 of the License. * * This program 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 for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define PERROR(_m, _a...) \ do { \ int __saved_errno = errno; \ fprintf(stderr, "ERROR: " _m " (%d = %s)\n" , ## _a , \ __saved_errno, strerror(__saved_errno)); \ errno = __saved_errno; \ } while (0) typedef struct { int counter; } atomic_t; #define _atomic_read(v) ((v).counter) #include #include "xenbaked.h" /***** Compile time configuration of defaults ********************************/ /* when we've got more records than this waiting, we log it to the output */ #define NEW_DATA_THRESH 1 /* sleep for this long (milliseconds) between checking the trace buffers */ #define POLL_SLEEP_MILLIS 100 /* Size of time period represented by each sample */ #define MS_PER_SAMPLE 100 /* CPU Frequency */ #define MHZ #define CPU_FREQ 2660 MHZ /***** The code **************************************************************/ typedef struct settings_st { struct timespec poll_sleep; unsigned long new_data_thresh; unsigned long ms_per_sample; double cpu_freq; } settings_t; struct t_struct { const struct t_info *t_info; /* Structure with information about individual buffers */ struct t_buf **meta; /* Pointers to trace buffer metadata */ unsigned char **data; /* Pointers to trace buffer data areas */ }; settings_t opts; int interrupted = 0; /* gets set if we get a SIGHUP */ int rec_count = 0; int wakeups = 0; time_t start_time; int dom0_flips = 0; _new_qos_data *new_qos; _new_qos_data **cpu_qos_data; int global_cpu; uint64_t global_now; // array of currently running domains, indexed by cpu int *running = NULL; // number of cpu's on this platform int NCPU = 0; static void advance_next_datapoint(uint64_t); static void alloc_qos_data(int ncpu); static int process_record(int, struct t_rec *); static void qos_kill_thread(int domid); static void init_current(int ncpu) { running = calloc(ncpu, sizeof(int)); NCPU = ncpu; printf("Initialized with %d %s\n", ncpu, (ncpu == 1) ? "cpu" : "cpu's"); } static int is_current(int domain, int cpu) { // int i; // for (i=0; icycles, x->event, x->data[0]); } #endif /** * millis_to_timespec - convert a time in milliseconds to a struct timespec * @millis: time interval in milliseconds */ static struct timespec millis_to_timespec(unsigned long millis) { struct timespec spec; spec.tv_sec = millis / 1000; spec.tv_nsec = (millis % 1000) * 1000; return spec; } typedef struct { int event_count; int event_id; char *text; } stat_map_t; stat_map_t stat_map[] = { { 0, 0, "Other" }, { 0, TRC_SCHED_DOM_ADD, "Add Domain" }, { 0, TRC_SCHED_DOM_REM, "Remove Domain" }, { 0, TRC_SCHED_SLEEP, "Sleep" }, { 0, TRC_SCHED_WAKE, "Wake" }, { 0, TRC_SCHED_BLOCK, "Block" }, { 0, TRC_SCHED_SWITCH, "Switch" }, { 0, TRC_SCHED_S_TIMER_FN, "Timer Func"}, { 0, TRC_SCHED_SWITCH_INFPREV, "Switch Prev" }, { 0, TRC_SCHED_SWITCH_INFNEXT, "Switch Next" }, { 0, TRC_MEM_PAGE_GRANT_MAP, "Page Map" }, { 0, TRC_MEM_PAGE_
/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

// NOTE: This is still WIP.
(* techmap_celltype = "$alu" *)
module _80_altera_a10gx_alu (A, B, CI, BI, X, Y, CO);
   parameter A_SIGNED = 0;
   parameter B_SIGNED = 0;
   parameter A_WIDTH  = 1;
   parameter B_WIDTH  = 1;
   parameter Y_WIDTH  = 1;

	input [A_WIDTH-1:0] A;
	input [B_WIDTH-1:0] B;
	output [Y_WIDTH-1:0] X, Y;

	input CI, BI;
	//output [Y_WIDTH-1:0] CO;
        output                 CO;

	wire _TECHMAP_FAIL_ = Y_WIDTH <= 4;

	wire [Y_WIDTH-1:0] A_buf, B_buf;
	\$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf));
	\$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf));

	wire [Y_WIDTH-1:0] AA = A_buf;
	wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf;
	//wire [Y_WIDTH:0] C = {CO, CI};
        wire [Y_WIDTH+1:0] COx;
        wire [Y_WIDTH+1:0] C = {COx, CI};

	/* Start implementation */
	(* keep *) fiftyfivenm_lcell_comb #(.lut_mask(16'b0000_0000_1010_1010), .sum_lutc_input("cin")) carry_start (.cout(COx[0]), .dataa(C[0]), .datab(1'b1), .datac(1'b1), .datad(1'b1));

	genvar i;
	generate for (i = 0; i < Y_WIDTH; i = i + 1) begin: slice
	  if(i==Y_WIDTH-1) begin
	    (* keep *) fiftyfivenm_lcell_comb #(.lut_mask(16'b1111_0000_1110_0000), .sum_lutc_input("cin")) carry_end (.combout(COx[Y_WIDTH]), .dataa(1'b1), .datab(1'b1), .datac(1'b1), .datad(1'b1), .cin(C[Y_WIDTH]));
            assign CO = COx[Y_WIDTH];
          end
	  else
	    fiftyfivenm_lcell_comb #(.lut_mask(16'b1001_0110_1110_1000), .sum_lutc_input("cin")) arith_cell (.combout(Y[i]), .cout(COx[i+1]), .dataa(AA[i]), .datab(BB[i]), .datac(1'b1), .datad(1'b1), .cin(C[i+1]));
	  end: slice
	endgenerate
	/* End implementation */
	assign X = AA ^ BB;

endmodule
new_qos->qdata[new].ns_passed = 0; new_qos->qdata[new].lost_records = 0; new_qos->qdata[new].flip_free_periods = 0; new_qos->qdata[new].timestamp = now; } static void qos_update_thread(int cpu, int domid, uint64_t now) { int n, id; uint64_t last_update_time, start; int64_t time_since_update, run_time = 0; id = indexof(domid); n = new_qos->next_datapoint; last_update_time = new_qos->domain_info[id].last_update_time; time_since_update = now - last_update_time; if (time_since_update < 0) { // what happened here? either a timestamp wraparound, or more likely, // a slight inconsistency among timestamps from various cpu's if (-time_since_update < billion) { // fairly small difference, let's just adjust 'now' to be a little // beyond last_update_time time_since_update = -time_since_update; } else if ( ((~0ULL - last_update_time) < billion) && (now < billion) ) { // difference is huge, must be a wraparound // last_update time should be "near" ~0ULL, // and now should be "near" 0 time_since_update = now + (~0ULL - last_update_time); printf("time wraparound\n"); } else { // none of the above, may be an out of order record // no good solution, just ignore and update again later return; } } new_qos->domain_info[id].last_update_time = now; if (new_qos->domain_info[id].runnable_at_last_update && is_current(domid, cpu)) { start = new_qos->domain_info[id].start_time; if (start > now) { // wrapped around run_time = now + (~0ULL - start); // this could happen if there is nothing going on within a cpu; // in this case the idle domain would run forever // printf("warning: start > now\n"); } else run_time = now - start; // if (run_time < 0) // should not happen // printf("warning: run_time < 0; start = %lld now= %lld\n", start, now); new_qos->domain_info[id].ns_oncpu_since_boot += run_time; new_qos->domain_info[id].start_time = now; new_qos->domain_info[id].ns_since_boot += time_since_update; new_qos->qdata[n].ns_gotten[id] += run_time; // if (domid == 0 && cpu == 1) // printf("adding run time for dom0 on cpu1\r\n"); } new_qos->domain_info[id].runnable_at_last_update = domain_runnable(domid); update_blocked_time(domid, now); // how much time passed since this datapoint was updated? if (now >= new_qos->qdata[n].timestamp) { // all is right with the world, time is increasing new_qos->qdata[n].ns_passed += (now - new_qos->qdata[n].timestamp); } else { // time wrapped around //new_qos->qdata[n].ns_passed += (now + (~0LL - new_qos->qdata[n].timestamp)); // printf("why timewrap?\r\n"); } new_qos->qdata[n].timestamp = now; } // called by dump routines to update all structures static void qos_update_all(uint64_t now, int cpu) { int i; for (i=0; idomain_info[i].in_use) qos_update_thread(cpu, new_qos->domain_info[i].id, now); } static void qos_update_thread_stats(int cpu, int domid, uint64_t now) { if (new_qos->qdata[new_qos->next_datapoint].ns_passed > (million*opts.ms_per_sample)) { qos_update_all(now, cpu); advance_next_datapoint(now); return; } qos_update_thread(cpu, domid, now); } // called when a new thread gets the cpu static void qos_switch_in(int cpu, int domid, uint64_t now, unsigned long ns_alloc, unsigned long ns_waited) { int idx = indexof(domid); new_qos->domain_info[idx].runnable = 1; update_blocked_time(domid, now); new_qos->domain_info[idx].blocked_start_time = 0; // invalidate new_qos->domain_info[idx].runnable_start_time = 0; // invalidate //runnable_start_time[idx] = 0; new_qos->domain_info[idx].start_time = now; new_qos->qdata[new_qos->next_datapoint].switchin_count[idx]++; new_qos->qdata[new_qos->next_datapoint].ns_allocated[idx] += ns_alloc; new_qos->qdata[new_qos->next_datapoint].ns_waiting[idx] += ns_waited; qos_update_thread_stats(cpu, domid, now); set_current(cpu, domid); // count up page flips for dom0 execution if (domid == 0) dom0_flips = 0; } // called when the current thread is taken off the cpu static void qos_switch_out(int cpu, int domid, uint64_t now, unsigned long gotten) { int idx = indexof(domid); int n; if (!is_current(domid, cpu)) { // printf("switching out domain %d but it is not current. gotten=%ld\r\n", id, gotten); } if (gotten == 0) { printf("gotten==0 in qos_switchout(domid=%d)\n", domid); } if (gotten < 100) { printf("gotten<100ns in qos_switchout(domid=%d)\n", domid); } n = new_qos->next_datapoint; #if 0 new_qos->qdata[n].ns_gotten[idx] += gotten; if (gotten > new_qos->qdata[n].ns_passed) printf("inconsistency #257, diff = %lld\n", gotten - new_qos->qdata[n].ns_passed ); #endif new_qos->domain_info[idx].ns_oncpu_since_boot += gotten; new_qos->domain_info[idx].runnable_start_time = now; // runnable_start_time[id] = now; qos_update_thread_stats(cpu, domid, now); // process dom0 page flips if (domid == 0) if (dom0_flips == 0) new_qos->qdata[n].flip_free_periods++; } // called when domain is put to sleep, may also be called // when thread is already asleep static void qos_state_sleeping(int cpu, int domid, uint64_t now) { int idx; if (!domain_runnable(domid)) // double call? return; idx = indexof(domid); new_qos->domain_info[idx].runnable = 0; new_qos->domain_info[idx].blocked_start_time = now; new_qos->domain_info[idx].runnable_start_time = 0; // invalidate // runnable_start_time[idx] = 0; // invalidate qos_update_thread_stats(cpu, domid, now); } // domain died, presume it's dead on all cpu's, not just mostly dead static void qos_kill_thread(int domid) { int cpu; for (cpu=0; cpudomain_info[indexof(domid)].in_use = 0; } } // called when thread becomes runnable, may also be called // when thread is already runnable static void qos_state_runnable(int cpu, int domid, uint64_t now) { int idx; qos_update_thread_stats(cpu, domid, now); if (domain_runnable(domid)) // double call? return; idx = indexof(domid); new_qos->domain_info[idx].runnable = 1; update_blocked_time(domid, now); new_qos->domain_info[idx].blocked_start_time = 0; /* invalidate */ new_qos->domain_info[idx].runnable_start_time = now; // runnable_start_time[id] = now; } static void qos_count_packets(domid_t domid, uint64_t now) { int i, idx = indexof(domid); _new_qos_data *cpu_data; for (i=0; idomain_info[idx].in_use) { cpu_data->qdata[cpu_data->next_datapoint].io_count[idx]++; } } new_qos->qdata[new_qos->next_datapoint].io_count[0]++; dom0_flips++; } static int process_record(int cpu, struct t_rec *r) { uint64_t now = 0; uint32_t *extra_u32 = r->u.nocycles.extra_u32; new_qos = cpu_qos_data[cpu]; rec_count++; if ( r->cycles_included ) { now = ((uint64_t)r->u.cycles.cycles_hi << 32) | r->u.cycles.cycles_lo; now = ((double)now) / (opts.cpu_freq / 1000.0); extra_u32 = r->u.cycles.extra_u32; } global_now = now; global_cpu = cpu; log_event(r->event); switch (r->event) { case TRC_SCHED_SWITCH_INFPREV: // domain data[0] just switched out and received data[1] ns of cpu time qos_switch_out(cpu, extra_u32[0], now, extra_u32[1]); // printf("ns_gotten %ld\n", extra_u32[1]); break; case TRC_SCHED_SWITCH_INFNEXT: // domain data[0] just switched in and // waited data[1] ns, and was allocated data[2] ns of cpu time qos_switch_in(cpu, extra_u32[0], now, extra_u32[2], extra_u32[1]); break; case TRC_SCHED_DOM_ADD: (void) indexof(extra_u32[0]); break; case TRC_SCHED_DOM_REM: qos_kill_thread(extra_u32[0]); break; case TRC_SCHED_SLEEP: qos_state_sleeping(cpu, extra_u32[0], now); break; case TRC_SCHED_WAKE: qos_state_runnable(cpu, extra_u32[0], now); break; case TRC_SCHED_BLOCK: qos_state_sleeping(cpu, extra_u32[0], now); break; case TRC_MEM_PAGE_GRANT_TRANSFER: qos_count_packets(extra_u32[0], now); break; default: break; } new_qos = NULL; return 4 + (r->cycles_included ? 8 : 0) + (r->extra_u32 * 4); }