Author: fabient
Date: Mon Aug  9 14:30:45 2010
New Revision: 211099
URL: http://svn.freebsd.org/changeset/base/211099

Log:
  MFC r210794:
  Allow file as a top source, it works with socket now.
  This will allow top monitoring using socket/ssh tunnelling
  of system without local symbols.
  
  client:
  pmcstat -R <ip>:<port> -T -r <symbolspath>
  monitored device:
  pmcstat -Sinstructions -O <ip>:<port>
  
  - Move the file read in the event loop
  - Initialize and clean log in all cases
  - Preserve global stats value during top refresh
  - Fix the rtld/line resolver that ignore '-r' prefix
  - Support socket for '-R' (server mode)
  - Display the statistics when exiting top mode

Modified:
  stable/7/usr.sbin/pmcstat/pmcstat.c
  stable/7/usr.sbin/pmcstat/pmcstat_log.c
Directory Properties:
  stable/7/usr.sbin/pmcstat/   (props changed)

Modified: stable/7/usr.sbin/pmcstat/pmcstat.c
==============================================================================
--- stable/7/usr.sbin/pmcstat/pmcstat.c Mon Aug  9 14:29:23 2010        
(r211098)
+++ stable/7/usr.sbin/pmcstat/pmcstat.c Mon Aug  9 14:30:45 2010        
(r211099)
@@ -169,8 +169,7 @@ pmcstat_cleanup(void)
                args.pa_logparser = NULL;
        }
 
-       if (args.pa_flags & (FLAG_HAS_PIPE | FLAG_HAS_OUTPUT_LOGFILE))
-               pmcstat_shutdown_logging();
+       pmcstat_shutdown_logging();
 }
 
 void
@@ -559,7 +558,7 @@ main(int argc, char **argv)
        int do_print;
        size_t dummy;
        int graphdepth;
-       int pipefd[2];
+       int pipefd[2], rfd;
        int use_cumulative_counts;
        short cf, cb;
        uint32_t cpumask;
@@ -1001,11 +1000,6 @@ main(int argc, char **argv)
            (args.pa_flags & FLAG_READ_LOGFILE) == 0)
            errx(EX_USAGE, "ERROR: option -M is only used with -g/-R.");
 
-       /* -T is incompatible with -R (replay logfile is a TODO) */
-       if ((args.pa_flags & FLAG_DO_TOP) &&
-           (args.pa_flags & FLAG_READ_LOGFILE))
-               errx(EX_USAGE, "ERROR: option -T is incompatible with -R.");
-
        /*
         * Disallow textual output of sampling PMCs if counting PMCs
         * have also been asked for, mostly because the combined output
@@ -1066,7 +1060,22 @@ main(int argc, char **argv)
                            graphfilename);
        }
 
-       /* if we've been asked to process a log file, do that and exit */
+       /* if we've been asked to process a log file, skip init */
+       if ((args.pa_flags & FLAG_READ_LOGFILE) == 0) {
+               if (pmc_init() < 0)
+                       err(EX_UNAVAILABLE,
+                           "ERROR: Initialization of the pmc(3) library 
failed");
+
+               if ((npmc = pmc_npmc(0)) < 0) /* assume all CPUs are identical 
*/
+                       err(EX_OSERR, "ERROR: Cannot determine the number of 
PMCs "
+                           "on CPU %d", 0);
+       }
+
+       /* Allocate a kqueue */
+       if ((pmcstat_kq = kqueue()) < 0)
+               err(EX_OSERR, "ERROR: Cannot allocate kqueue");
+
+       /* Setup the logfile as the source. */
        if (args.pa_flags & FLAG_READ_LOGFILE) {
                /*
                 * Print the log in textual form if we haven't been
@@ -1076,28 +1085,17 @@ main(int argc, char **argv)
                        args.pa_flags |= FLAG_DO_PRINT;
 
                pmcstat_initialize_logging();
-               args.pa_logfd = pmcstat_open_log(args.pa_inputpath,
+               rfd = pmcstat_open_log(args.pa_inputpath,
                    PMCSTAT_OPEN_FOR_READ);
-               if ((args.pa_logparser = pmclog_open(args.pa_logfd)) == NULL)
+               if ((args.pa_logparser = pmclog_open(rfd)) == NULL)
                        err(EX_OSERR, "ERROR: Cannot create parser");
-               pmcstat_process_log();
-               pmcstat_shutdown_logging();
-               exit(EX_OK);
+               if (fcntl(rfd, F_SETFL, O_NONBLOCK) < 0)
+                       err(EX_OSERR, "ERROR: fcntl(2) failed");
+               EV_SET(&kev, rfd, EVFILT_READ, EV_ADD,
+                   0, 0, NULL);
+               if (kevent(pmcstat_kq, &kev, 1, NULL, 0, NULL) < 0)
+                       err(EX_OSERR, "ERROR: Cannot register kevent");
        }
-
-       /* otherwise, we've been asked to collect data */
-       if (pmc_init() < 0)
-               err(EX_UNAVAILABLE,
-                   "ERROR: Initialization of the pmc(3) library failed");
-
-       if ((npmc = pmc_npmc(0)) < 0) /* assume all CPUs are identical */
-               err(EX_OSERR, "ERROR: Cannot determine the number of PMCs "
-                   "on CPU %d", 0);
-
-       /* Allocate a kqueue */
-       if ((pmcstat_kq = kqueue()) < 0)
-               err(EX_OSERR, "ERROR: Cannot allocate kqueue");
-
        /*
         * Configure the specified log file or setup a default log
         * consumer via a pipe.
@@ -1140,6 +1138,7 @@ main(int argc, char **argv)
            (args.pa_flags & FLAG_HAS_OUTPUT_LOGFILE);
 
        /*
+       if (args.pa_flags & FLAG_READ_LOGFILE) {
         * Allocate PMCs.
         */
 
@@ -1272,10 +1271,8 @@ main(int argc, char **argv)
        if (args.pa_flags & FLAG_HAS_COMMANDLINE)
                pmcstat_start_process();
 
-       /* initialize logging if printing the configured log */
-       if ((args.pa_flags & (FLAG_DO_PRINT | FLAG_DO_TOP)) &&
-           (args.pa_flags & (FLAG_HAS_PIPE | FLAG_HAS_OUTPUT_LOGFILE)))
-               pmcstat_initialize_logging();
+       /* initialize logging */
+       pmcstat_initialize_logging();
 
        /* Handle SIGINT using the kqueue loop */
        sa.sa_handler = SIG_IGN;
@@ -1338,16 +1335,13 @@ main(int argc, char **argv)
 
                switch (kev.filter) {
                case EVFILT_PROC:  /* target has exited */
-                       if (args.pa_flags & (FLAG_HAS_OUTPUT_LOGFILE |
-                               FLAG_HAS_PIPE))
-                               runstate = pmcstat_close_log();
-                       else
-                               runstate = PMCSTAT_FINISHED;
+                       runstate = pmcstat_close_log();
                        do_print = 1;
                        break;
 
                case EVFILT_READ:  /* log file data is present */
-                       if (kev.ident == (unsigned)fileno(stdin)) {
+                       if (kev.ident == (unsigned)fileno(stdin) &&
+                           (args.pa_flags & FLAG_DO_TOP)) {
                                if (pmcstat_keypress_log())
                                        runstate = pmcstat_close_log();
                        } else
@@ -1370,15 +1364,8 @@ main(int argc, char **argv)
                                 * of its targets, or if logfile
                                 * writes encounter an error.
                                 */
-                               if (args.pa_flags & (FLAG_HAS_OUTPUT_LOGFILE |
-                                   FLAG_HAS_PIPE)) {
-                                       runstate = pmcstat_close_log();
-                                       if (args.pa_flags &
-                                           (FLAG_DO_PRINT|FLAG_DO_ANALYSIS))
-                                               pmcstat_process_log();
-                               }
+                               runstate = pmcstat_close_log();
                                do_print = 1; /* print PMCs at exit */
-                               runstate = PMCSTAT_FINISHED;
                        } else if (kev.ident == SIGINT) {
                                /* Kill the child process if we started it */
                                if (args.pa_flags & FLAG_HAS_COMMANDLINE)
@@ -1386,7 +1373,7 @@ main(int argc, char **argv)
                                /* Close the pipe to self, if present. */
                                if (args.pa_flags & FLAG_HAS_PIPE)
                                        (void) close(pipefd[READPIPEFD]);
-                               runstate = PMCSTAT_FINISHED;
+                               runstate = pmcstat_close_log();
                        } else if (kev.ident == SIGWINCH) {
                                if (ioctl(fileno(args.pa_printfile),
                                        TIOCGWINSZ, &ws) < 0)

Modified: stable/7/usr.sbin/pmcstat/pmcstat_log.c
==============================================================================
--- stable/7/usr.sbin/pmcstat/pmcstat_log.c     Mon Aug  9 14:29:23 2010        
(r211098)
+++ stable/7/usr.sbin/pmcstat/pmcstat_log.c     Mon Aug  9 14:30:45 2010        
(r211099)
@@ -141,6 +141,7 @@ struct pmcstat_image_hash_list pmcstat_i
 struct pmcstat_process_hash_list pmcstat_process_hash[PMCSTAT_NHASH];
 
 struct pmcstat_stats pmcstat_stats; /* statistics */
+int ps_samples_period; /* samples count between top refresh. */
 
 struct pmcstat_process *pmcstat_kernproc; /* kernel 'process' */
 
@@ -247,7 +248,7 @@ static int  pmcstat_string_compute_hash(c
 static void pmcstat_string_initialize(void);
 static int     pmcstat_string_lookup_hash(pmcstat_interned_string _is);
 static void pmcstat_string_shutdown(void);
-static void pmcstat_stats_reset(void);
+static void pmcstat_stats_reset(int _reset_global);
 
 /*
  * A simple implementation of interned strings.  Each interned string
@@ -276,7 +277,7 @@ int pmcstat_npmcs;
 int pmcstat_pause;
 
 static void
-pmcstat_stats_reset(void)
+pmcstat_stats_reset(int reset_global)
 {
        struct pmcstat_pmcrecord *pr;
 
@@ -285,9 +286,11 @@ pmcstat_stats_reset(void)
                pr->pr_samples = 0;
                pr->pr_dubious_frames = 0;
        }
+       ps_samples_period = 0;
 
        /* Flush global stats. */
-       bzero(&pmcstat_stats, sizeof(struct pmcstat_stats));
+       if (reset_global)
+               bzero(&pmcstat_stats, sizeof(struct pmcstat_stats));
 }
 
 /*
@@ -606,7 +609,7 @@ pmcstat_image_get_elf_params(struct pmcs
        GElf_Phdr ph;
        GElf_Shdr sh;
        enum pmcstat_image_type image_type;
-       char buffer[PATH_MAX];
+       char buffer[PATH_MAX], rtldpath[PATH_MAX];
 
        assert(image->pi_type == PMCSTAT_IMAGE_UNKNOWN);
 
@@ -686,9 +689,10 @@ pmcstat_image_get_elf_params(struct pmcs
                                            buffer, elf_errmsg(-1));
                                        goto done;
                                }
+                               snprintf(rtldpath, sizeof(rtldpath), "%s%s",
+                                   args.pa_fsroot, elfbase + ph.p_offset);
                                image->pi_dynlinkerpath =
-                                   pmcstat_string_intern(elfbase +
-                                       ph.p_offset);
+                                   pmcstat_string_intern(rtldpath);
                                break;
                        case PT_LOAD:
                                if (ph.p_offset == 0)
@@ -944,11 +948,13 @@ pmcstat_image_addr2line(struct pmcstat_i
        int fd;
 
        if (image->pi_addr2line == NULL) {
-               snprintf(imagepath, sizeof(imagepath), "%s.symbols",
+               snprintf(imagepath, sizeof(imagepath), "%s%s.symbols",
+                   args.pa_fsroot,
                    pmcstat_string_unintern(image->pi_fullpath));
                fd = open(imagepath, O_RDONLY);
                if (fd < 0) {
-                       snprintf(imagepath, sizeof(imagepath), "%s",
+                       snprintf(imagepath, sizeof(imagepath), "%s%s",
+                           args.pa_fsroot,
                            pmcstat_string_unintern(image->pi_fullpath));
                } else
                        close(fd);
@@ -1399,6 +1405,7 @@ pmcstat_analyze_log(void)
                         * bin inside this.
                         */
                        pmcstat_stats.ps_samples_total++;
+                       ps_samples_period++;
 
                        pc = ev.pl_u.pl_s.pl_pc;
                        pp = pmcstat_process_lookup(ev.pl_u.pl_s.pl_pid,
@@ -1425,6 +1432,7 @@ pmcstat_analyze_log(void)
 
                case PMCLOG_TYPE_CALLCHAIN:
                        pmcstat_stats.ps_samples_total++;
+                       ps_samples_period++;
 
                        cpuflags = ev.pl_u.pl_cc.pl_cpuflags;
                        cpu = PMC_CALLCHAIN_CPUFLAGS_TO_CPU(cpuflags);
@@ -1691,8 +1699,15 @@ pmcstat_print_log(void)
 int
 pmcstat_close_log(void)
 {
-       if (pmc_flush_logfile() < 0)
-               err(EX_OSERR, "ERROR: logging failed");
+       /* If a local logfile is configured ask the kernel to stop
+        * and flush data. Kernel will close the file when data is flushed
+        * so keep the status to EXITING.
+        */
+       if (args.pa_logfd != -1) {
+               if (pmc_flush_logfile() < 0)
+                       err(EX_OSERR, "ERROR: logging failed");
+       }
+
        return (args.pa_flags & FLAG_HAS_PIPE ? PMCSTAT_EXITING :
            PMCSTAT_FINISHED);
 }
@@ -1709,7 +1724,7 @@ pmcstat_close_log(void)
 int
 pmcstat_open_log(const char *path, int mode)
 {
-       int error, fd;
+       int error, fd, cfd;
        size_t hlen;
        const char *p, *errstr;
        struct addrinfo hints, *res, *res0;
@@ -1730,7 +1745,7 @@ pmcstat_open_log(const char *path, int m
         */
        if (path[0] == '-' && path[1] == '\0')
                fd = (mode == PMCSTAT_OPEN_FOR_READ) ? 0 : 1;
-       else if (mode == PMCSTAT_OPEN_FOR_WRITE && path[0] != '/' &&
+       else if (path[0] != '/' &&
            path[0] != '.' && strchr(path, ':') != NULL) {
 
                p = strrchr(path, ':');
@@ -1759,11 +1774,29 @@ pmcstat_open_log(const char *path, int m
                                errstr = strerror(errno);
                                continue;
                        }
-                       if (connect(fd, res->ai_addr, res->ai_addrlen) < 0) {
-                               errstr = strerror(errno);
+                       if (mode == PMCSTAT_OPEN_FOR_READ) {
+                               if (bind(fd, res->ai_addr, res->ai_addrlen) < 
0) {
+                                       errstr = strerror(errno);
+                                       (void) close(fd);
+                                       fd = -1;
+                                       continue;
+                               }
+                               listen(fd, 1);
+                               cfd = accept(fd, NULL, NULL);
                                (void) close(fd);
-                               fd = -1;
-                               continue;
+                               if (cfd < 0) {
+                                       errstr = strerror(errno);
+                                       fd = -1;
+                                       break;
+                               }
+                               fd = cfd;
+                       } else {
+                               if (connect(fd, res->ai_addr, res->ai_addrlen) 
< 0) {
+                                       errstr = strerror(errno);
+                                       (void) close(fd);
+                                       fd = -1;
+                                       continue;
+                               }
                        }
                        errstr = NULL;
                        break;
@@ -1833,9 +1866,8 @@ pmcstat_refresh_top(void)
                    pmcstat_pmcinfilter);
 
        /* Format samples count. */
-       if (pmcstat_stats.ps_samples_total > 0)
-               v = (pmcpr->pr_samples * 100.0) /
-                   pmcstat_stats.ps_samples_total;
+       if (ps_samples_period > 0)
+               v = (pmcpr->pr_samples * 100.0) / ps_samples_period;
        else
                v = 0.;
        v_attrs = PMCSTAT_ATTRPERCENT(v);
@@ -1872,7 +1904,7 @@ pmcstat_changefilter(void)
 
                do {
                        pmcr = pmcstat_pmcindex_to_pmcr(pmcstat_pmcinfilter);
-                       if (pmcr == pmcr->pr_merge)
+                       if (pmcr == NULL || pmcr == pmcr->pr_merge)
                                break;
 
                        pmcstat_pmcinfilter++;
@@ -1915,7 +1947,7 @@ pmcstat_keypress_log(void)
                 */
                if (plugins[args.pa_plugin].pl_shutdown != NULL)
                        plugins[args.pa_plugin].pl_shutdown(NULL);
-               pmcstat_stats_reset();
+               pmcstat_stats_reset(0);
                if (plugins[args.pa_plugin].pl_init != NULL)
                        plugins[args.pa_plugin].pl_init();
 
@@ -1936,7 +1968,7 @@ pmcstat_keypress_log(void)
                } while (plugins[args.pa_plugin].pl_topdisplay == NULL);
 
                /* Open new plugin. */
-               pmcstat_stats_reset();
+               pmcstat_stats_reset(0);
                if (plugins[args.pa_plugin].pl_init != NULL)
                        plugins[args.pa_plugin].pl_init();
                wprintw(w, "switching to plugin %s",
@@ -1986,7 +2018,7 @@ pmcstat_display_log(void)
        if (args.pa_topmode == PMCSTAT_TOP_DELTA) {
                if (plugins[args.pa_plugin].pl_shutdown != NULL)
                        plugins[args.pa_plugin].pl_shutdown(NULL);
-               pmcstat_stats_reset();
+               pmcstat_stats_reset(0);
                if (plugins[args.pa_plugin].pl_init != NULL)
                        plugins[args.pa_plugin].pl_init();
        }
@@ -2130,8 +2162,7 @@ pmcstat_shutdown_logging(void)
                            N, pmcstat_stats.ps_##V);                   \
        } while (0)
 
-       if (args.pa_verbosity >= 1 && (args.pa_flags & FLAG_DO_ANALYSIS) &&
-           (args.pa_flags & FLAG_DO_TOP) == 0) {
+       if (args.pa_verbosity >= 1 && (args.pa_flags & FLAG_DO_ANALYSIS)) {
                (void) fprintf(args.pa_printfile, "CONVERSION STATISTICS:\n");
                PRINT("#exec/a.out", exec_aout);
                PRINT("#exec/elf", exec_elf);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to