Print this page
4471 DTrace count() with histogram
4472 DTrace full width distribution histograms
4473 DTrace frequency trails


   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * Copyright (c) 2011, Joyent, Inc. All rights reserved.
  29  * Copyright (c) 2012 by Delphix. All rights reserved.
  30  */
  31 
  32 #include <stdlib.h>
  33 #include <strings.h>
  34 #include <errno.h>
  35 #include <unistd.h>
  36 #include <dt_impl.h>
  37 #include <assert.h>
  38 #include <alloca.h>
  39 #include <limits.h>
  40 
  41 #define DTRACE_AHASHSIZE        32779           /* big 'ol prime */
  42 
  43 /*
  44  * Because qsort(3C) does not allow an argument to be passed to a comparison
  45  * function, the variables that affect comparison must regrettably be global;
  46  * they are protected by a global static lock, dt_qsort_lock.
  47  */
  48 static pthread_mutex_t dt_qsort_lock = PTHREAD_MUTEX_INITIALIZER;


1274 {
1275         dt_ahashent_t *h, *next;
1276         dt_ahash_t *hash = &dtp->dt_aggregate.dtat_hash;
1277 
1278         for (h = hash->dtah_all; h != NULL; h = next) {
1279                 /*
1280                  * dt_aggwalk_rval() can potentially remove the current hash
1281                  * entry; we need to load the next hash entry before calling
1282                  * into it.
1283                  */
1284                 next = h->dtahe_nextall;
1285 
1286                 if (dt_aggwalk_rval(dtp, h, func(&h->dtahe_data, arg)) == -1)
1287                         return (-1);
1288         }
1289 
1290         return (0);
1291 }
1292 
1293 static int

































































































































































































































1294 dt_aggregate_walk_sorted(dtrace_hdl_t *dtp,
1295     dtrace_aggregate_f *func, void *arg,
1296     int (*sfunc)(const void *, const void *))
1297 {
1298         dt_aggregate_t *agp = &dtp->dt_aggregate;
1299         dt_ahashent_t *h, **sorted;
1300         dt_ahash_t *hash = &agp->dtat_hash;
1301         size_t i, nentries = 0;

















1302 
1303         for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall)
1304                 nentries++;
1305 
1306         sorted = dt_alloc(dtp, nentries * sizeof (dt_ahashent_t *));
1307 
1308         if (sorted == NULL)
1309                 return (-1);
1310 
1311         for (h = hash->dtah_all, i = 0; h != NULL; h = h->dtahe_nextall)
1312                 sorted[i++] = h;
1313 
1314         (void) pthread_mutex_lock(&dt_qsort_lock);
1315 
1316         if (sfunc == NULL) {
1317                 dt_aggregate_qsort(dtp, sorted, nentries,
1318                     sizeof (dt_ahashent_t *), NULL);
1319         } else {
1320                 /*
1321                  * If we've been explicitly passed a sorting function,
1322                  * we'll use that -- ignoring the values of the "aggsortrev",
1323                  * "aggsortkey" and "aggsortkeypos" options.
1324                  */
1325                 qsort(sorted, nentries, sizeof (dt_ahashent_t *), sfunc);
1326         }
1327 
1328         (void) pthread_mutex_unlock(&dt_qsort_lock);
1329 
1330         for (i = 0; i < nentries; i++) {
1331                 h = sorted[i];
1332 
1333                 if (dt_aggwalk_rval(dtp, h, func(&h->dtahe_data, arg)) == -1) {
1334                         dt_free(dtp, sorted);
1335                         return (-1);
1336                 }
1337         }
1338 








1339         dt_free(dtp, sorted);
1340         return (0);
1341 }
1342 
1343 int
1344 dtrace_aggregate_walk_sorted(dtrace_hdl_t *dtp,
1345     dtrace_aggregate_f *func, void *arg)
1346 {
1347         return (dt_aggregate_walk_sorted(dtp, func, arg, NULL));
1348 }
1349 
1350 int
1351 dtrace_aggregate_walk_keysorted(dtrace_hdl_t *dtp,
1352     dtrace_aggregate_f *func, void *arg)
1353 {
1354         return (dt_aggregate_walk_sorted(dtp, func,
1355             arg, dt_aggregate_varkeycmp));
1356 }
1357 
1358 int
1359 dtrace_aggregate_walk_valsorted(dtrace_hdl_t *dtp,
1360     dtrace_aggregate_f *func, void *arg)


1843 
1844         if (zaggdata != NULL) {
1845                 for (i = 0; i < naggvars; i++)
1846                         dt_free(dtp, zaggdata[i].dtahe_data.dtada_data);
1847         }
1848 
1849         dt_free(dtp, zaggdata);
1850         dt_free(dtp, sorted);
1851         dt_free(dtp, remap);
1852         dt_free(dtp, map);
1853 
1854         return (rval);
1855 }
1856 
1857 int
1858 dtrace_aggregate_print(dtrace_hdl_t *dtp, FILE *fp,
1859     dtrace_aggregate_walk_f *func)
1860 {
1861         dt_print_aggdata_t pd;
1862 


1863         pd.dtpa_dtp = dtp;
1864         pd.dtpa_fp = fp;
1865         pd.dtpa_allunprint = 1;
1866 
1867         if (func == NULL)
1868                 func = dtrace_aggregate_walk_sorted;
1869 
1870         if ((*func)(dtp, dt_print_agg, &pd) == -1)
1871                 return (dt_set_errno(dtp, dtp->dt_errno));
1872 
1873         return (0);
1874 }
1875 
1876 void
1877 dtrace_aggregate_clear(dtrace_hdl_t *dtp)
1878 {
1879         dt_aggregate_t *agp = &dtp->dt_aggregate;
1880         dt_ahash_t *hash = &agp->dtat_hash;
1881         dt_ahashent_t *h;
1882         dtrace_aggdata_t *data;




   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  29  * Copyright (c) 2012 by Delphix. All rights reserved.
  30  */
  31 
  32 #include <stdlib.h>
  33 #include <strings.h>
  34 #include <errno.h>
  35 #include <unistd.h>
  36 #include <dt_impl.h>
  37 #include <assert.h>
  38 #include <alloca.h>
  39 #include <limits.h>
  40 
  41 #define DTRACE_AHASHSIZE        32779           /* big 'ol prime */
  42 
  43 /*
  44  * Because qsort(3C) does not allow an argument to be passed to a comparison
  45  * function, the variables that affect comparison must regrettably be global;
  46  * they are protected by a global static lock, dt_qsort_lock.
  47  */
  48 static pthread_mutex_t dt_qsort_lock = PTHREAD_MUTEX_INITIALIZER;


1274 {
1275         dt_ahashent_t *h, *next;
1276         dt_ahash_t *hash = &dtp->dt_aggregate.dtat_hash;
1277 
1278         for (h = hash->dtah_all; h != NULL; h = next) {
1279                 /*
1280                  * dt_aggwalk_rval() can potentially remove the current hash
1281                  * entry; we need to load the next hash entry before calling
1282                  * into it.
1283                  */
1284                 next = h->dtahe_nextall;
1285 
1286                 if (dt_aggwalk_rval(dtp, h, func(&h->dtahe_data, arg)) == -1)
1287                         return (-1);
1288         }
1289 
1290         return (0);
1291 }
1292 
1293 static int
1294 dt_aggregate_total(dtrace_hdl_t *dtp, boolean_t clear)
1295 {
1296         dt_ahashent_t *h;
1297         dtrace_aggdata_t **total;
1298         dtrace_aggid_t max = DTRACE_AGGVARIDNONE, id;
1299         dt_aggregate_t *agp = &dtp->dt_aggregate;
1300         dt_ahash_t *hash = &agp->dtat_hash;
1301         uint32_t tflags;
1302 
1303         tflags = DTRACE_A_TOTAL | DTRACE_A_HASNEGATIVES | DTRACE_A_HASPOSITIVES;
1304 
1305         /*
1306          * If we need to deliver per-aggregation totals, we're going to take
1307          * three passes over the aggregate:  one to clear everything out and
1308          * determine our maximum aggregation ID, one to actually total
1309          * everything up, and a final pass to assign the totals to the
1310          * individual elements.
1311          */
1312         for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
1313                 dtrace_aggdata_t *aggdata = &h->dtahe_data;
1314 
1315                 if ((id = dt_aggregate_aggvarid(h)) > max)
1316                         max = id;
1317 
1318                 aggdata->dtada_total = 0;
1319                 aggdata->dtada_flags &= ~tflags;
1320         }
1321 
1322         if (clear || max == DTRACE_AGGVARIDNONE)
1323                 return (0);
1324 
1325         total = dt_zalloc(dtp, (max + 1) * sizeof (dtrace_aggdata_t *));
1326 
1327         if (total == NULL)
1328                 return (-1);
1329 
1330         for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
1331                 dtrace_aggdata_t *aggdata = &h->dtahe_data;
1332                 dtrace_aggdesc_t *agg = aggdata->dtada_desc;
1333                 dtrace_recdesc_t *rec;
1334                 caddr_t data;
1335                 int64_t val, *addr;
1336 
1337                 rec = &agg->dtagd_rec[agg->dtagd_nrecs - 1];
1338                 data = aggdata->dtada_data;
1339                 addr = (int64_t *)(uintptr_t)(data + rec->dtrd_offset);
1340 
1341                 switch (rec->dtrd_action) {
1342                 case DTRACEAGG_STDDEV:
1343                         val = dt_stddev((uint64_t *)addr, 1);
1344                         break;
1345 
1346                 case DTRACEAGG_SUM:
1347                 case DTRACEAGG_COUNT:
1348                         val = *addr;
1349                         break;
1350 
1351                 case DTRACEAGG_AVG:
1352                         val = addr[0] ? (addr[1] / addr[0]) : 0;
1353                         break;
1354 
1355                 default:
1356                         continue;
1357                 }
1358 
1359                 if (total[agg->dtagd_varid] == NULL) {
1360                         total[agg->dtagd_varid] = aggdata;
1361                         aggdata->dtada_flags |= DTRACE_A_TOTAL;
1362                 } else {
1363                         aggdata = total[agg->dtagd_varid];
1364                 }
1365 
1366                 if (val > 0)
1367                         aggdata->dtada_flags |= DTRACE_A_HASPOSITIVES;
1368 
1369                 if (val < 0) {
1370                         aggdata->dtada_flags |= DTRACE_A_HASNEGATIVES;
1371                         val = -val;
1372                 }
1373 
1374                 if (dtp->dt_options[DTRACEOPT_AGGZOOM] != DTRACEOPT_UNSET) {
1375                         val = (int64_t)((long double)val *
1376                             (1 / DTRACE_AGGZOOM_MAX));
1377 
1378                         if (val > aggdata->dtada_total)
1379                                 aggdata->dtada_total = val;
1380                 } else {
1381                         aggdata->dtada_total += val;
1382                 }
1383         }
1384 
1385         /*
1386          * And now one final pass to set everyone's total.
1387          */
1388         for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
1389                 dtrace_aggdata_t *aggdata = &h->dtahe_data, *t;
1390                 dtrace_aggdesc_t *agg = aggdata->dtada_desc;
1391 
1392                 if ((t = total[agg->dtagd_varid]) == NULL || aggdata == t)
1393                         continue;
1394 
1395                 aggdata->dtada_total = t->dtada_total;
1396                 aggdata->dtada_flags |= (t->dtada_flags & tflags);
1397         }
1398 
1399         dt_free(dtp, total);
1400 
1401         return (0);
1402 }
1403 
1404 static int
1405 dt_aggregate_minmaxbin(dtrace_hdl_t *dtp, boolean_t clear)
1406 {
1407         dt_ahashent_t *h;
1408         dtrace_aggdata_t **minmax;
1409         dtrace_aggid_t max = DTRACE_AGGVARIDNONE, id;
1410         dt_aggregate_t *agp = &dtp->dt_aggregate;
1411         dt_ahash_t *hash = &agp->dtat_hash;
1412 
1413         for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
1414                 dtrace_aggdata_t *aggdata = &h->dtahe_data;
1415 
1416                 if ((id = dt_aggregate_aggvarid(h)) > max)
1417                         max = id;
1418 
1419                 aggdata->dtada_minbin = 0;
1420                 aggdata->dtada_maxbin = 0;
1421                 aggdata->dtada_flags &= ~DTRACE_A_MINMAXBIN;
1422         }
1423 
1424         if (clear || max == DTRACE_AGGVARIDNONE)
1425                 return (0);
1426 
1427         minmax = dt_zalloc(dtp, (max + 1) * sizeof (dtrace_aggdata_t *));
1428 
1429         if (minmax == NULL)
1430                 return (-1);
1431 
1432         for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
1433                 dtrace_aggdata_t *aggdata = &h->dtahe_data;
1434                 dtrace_aggdesc_t *agg = aggdata->dtada_desc;
1435                 dtrace_recdesc_t *rec;
1436                 caddr_t data;
1437                 int64_t *addr;
1438                 int minbin = -1, maxbin = -1, i;
1439                 int start = 0, size;
1440 
1441                 rec = &agg->dtagd_rec[agg->dtagd_nrecs - 1];
1442                 size = rec->dtrd_size / sizeof (int64_t);
1443                 data = aggdata->dtada_data;
1444                 addr = (int64_t *)(uintptr_t)(data + rec->dtrd_offset);
1445 
1446                 switch (rec->dtrd_action) {
1447                 case DTRACEAGG_LQUANTIZE:
1448                         /*
1449                          * For lquantize(), we always display the entire range
1450                          * of the aggregation when aggpack is set.
1451                          */
1452                         start = 1;
1453                         minbin = start;
1454                         maxbin = size - 1 - start;
1455                         break;
1456 
1457                 case DTRACEAGG_QUANTIZE:
1458                         for (i = start; i < size; i++) {
1459                                 if (!addr[i])
1460                                         continue;
1461 
1462                                 if (minbin == -1)
1463                                         minbin = i - start;
1464 
1465                                 maxbin = i - start;
1466                         }
1467 
1468                         if (minbin == -1) {
1469                                 /*
1470                                  * If we have no data (e.g., due to a clear()
1471                                  * or negative increments), we'll use the
1472                                  * zero bucket as both our min and max.
1473                                  */
1474                                 minbin = maxbin = DTRACE_QUANTIZE_ZEROBUCKET;
1475                         }
1476 
1477                         break;
1478 
1479                 default:
1480                         continue;
1481                 }
1482 
1483                 if (minmax[agg->dtagd_varid] == NULL) {
1484                         minmax[agg->dtagd_varid] = aggdata;
1485                         aggdata->dtada_flags |= DTRACE_A_MINMAXBIN;
1486                         aggdata->dtada_minbin = minbin;
1487                         aggdata->dtada_maxbin = maxbin;
1488                         continue;
1489                 }
1490 
1491                 if (minbin < minmax[agg->dtagd_varid]->dtada_minbin)
1492                         minmax[agg->dtagd_varid]->dtada_minbin = minbin;
1493 
1494                 if (maxbin > minmax[agg->dtagd_varid]->dtada_maxbin)
1495                         minmax[agg->dtagd_varid]->dtada_maxbin = maxbin;
1496         }
1497 
1498         /*
1499          * And now one final pass to set everyone's minbin and maxbin.
1500          */
1501         for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
1502                 dtrace_aggdata_t *aggdata = &h->dtahe_data, *mm;
1503                 dtrace_aggdesc_t *agg = aggdata->dtada_desc;
1504 
1505                 if ((mm = minmax[agg->dtagd_varid]) == NULL || aggdata == mm)
1506                         continue;
1507 
1508                 aggdata->dtada_minbin = mm->dtada_minbin;
1509                 aggdata->dtada_maxbin = mm->dtada_maxbin;
1510                 aggdata->dtada_flags |= DTRACE_A_MINMAXBIN;
1511         }
1512 
1513         dt_free(dtp, minmax);
1514 
1515         return (0);
1516 }
1517 
1518 static int
1519 dt_aggregate_walk_sorted(dtrace_hdl_t *dtp,
1520     dtrace_aggregate_f *func, void *arg,
1521     int (*sfunc)(const void *, const void *))
1522 {
1523         dt_aggregate_t *agp = &dtp->dt_aggregate;
1524         dt_ahashent_t *h, **sorted;
1525         dt_ahash_t *hash = &agp->dtat_hash;
1526         size_t i, nentries = 0;
1527         int rval = -1;
1528 
1529         agp->dtat_flags &= ~(DTRACE_A_TOTAL | DTRACE_A_MINMAXBIN);
1530 
1531         if (dtp->dt_options[DTRACEOPT_AGGHIST] != DTRACEOPT_UNSET) {
1532                 agp->dtat_flags |= DTRACE_A_TOTAL;
1533 
1534                 if (dt_aggregate_total(dtp, B_FALSE) != 0)
1535                         return (-1);
1536         }
1537 
1538         if (dtp->dt_options[DTRACEOPT_AGGPACK] != DTRACEOPT_UNSET) {
1539                 agp->dtat_flags |= DTRACE_A_MINMAXBIN;
1540 
1541                 if (dt_aggregate_minmaxbin(dtp, B_FALSE) != 0)
1542                         return (-1);
1543         }
1544 
1545         for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall)
1546                 nentries++;
1547 
1548         sorted = dt_alloc(dtp, nentries * sizeof (dt_ahashent_t *));
1549 
1550         if (sorted == NULL)
1551                 goto out;
1552 
1553         for (h = hash->dtah_all, i = 0; h != NULL; h = h->dtahe_nextall)
1554                 sorted[i++] = h;
1555 
1556         (void) pthread_mutex_lock(&dt_qsort_lock);
1557 
1558         if (sfunc == NULL) {
1559                 dt_aggregate_qsort(dtp, sorted, nentries,
1560                     sizeof (dt_ahashent_t *), NULL);
1561         } else {
1562                 /*
1563                  * If we've been explicitly passed a sorting function,
1564                  * we'll use that -- ignoring the values of the "aggsortrev",
1565                  * "aggsortkey" and "aggsortkeypos" options.
1566                  */
1567                 qsort(sorted, nentries, sizeof (dt_ahashent_t *), sfunc);
1568         }
1569 
1570         (void) pthread_mutex_unlock(&dt_qsort_lock);
1571 
1572         for (i = 0; i < nentries; i++) {
1573                 h = sorted[i];
1574 
1575                 if (dt_aggwalk_rval(dtp, h, func(&h->dtahe_data, arg)) == -1)
1576                         goto out;


1577         }
1578 
1579         rval = 0;
1580 out:
1581         if (agp->dtat_flags & DTRACE_A_TOTAL)
1582                 (void) dt_aggregate_total(dtp, B_TRUE);
1583 
1584         if (agp->dtat_flags & DTRACE_A_MINMAXBIN)
1585                 (void) dt_aggregate_minmaxbin(dtp, B_TRUE);
1586 
1587         dt_free(dtp, sorted);
1588         return (rval);
1589 }
1590 
1591 int
1592 dtrace_aggregate_walk_sorted(dtrace_hdl_t *dtp,
1593     dtrace_aggregate_f *func, void *arg)
1594 {
1595         return (dt_aggregate_walk_sorted(dtp, func, arg, NULL));
1596 }
1597 
1598 int
1599 dtrace_aggregate_walk_keysorted(dtrace_hdl_t *dtp,
1600     dtrace_aggregate_f *func, void *arg)
1601 {
1602         return (dt_aggregate_walk_sorted(dtp, func,
1603             arg, dt_aggregate_varkeycmp));
1604 }
1605 
1606 int
1607 dtrace_aggregate_walk_valsorted(dtrace_hdl_t *dtp,
1608     dtrace_aggregate_f *func, void *arg)


2091 
2092         if (zaggdata != NULL) {
2093                 for (i = 0; i < naggvars; i++)
2094                         dt_free(dtp, zaggdata[i].dtahe_data.dtada_data);
2095         }
2096 
2097         dt_free(dtp, zaggdata);
2098         dt_free(dtp, sorted);
2099         dt_free(dtp, remap);
2100         dt_free(dtp, map);
2101 
2102         return (rval);
2103 }
2104 
2105 int
2106 dtrace_aggregate_print(dtrace_hdl_t *dtp, FILE *fp,
2107     dtrace_aggregate_walk_f *func)
2108 {
2109         dt_print_aggdata_t pd;
2110 
2111         bzero(&pd, sizeof (pd));
2112 
2113         pd.dtpa_dtp = dtp;
2114         pd.dtpa_fp = fp;
2115         pd.dtpa_allunprint = 1;
2116 
2117         if (func == NULL)
2118                 func = dtrace_aggregate_walk_sorted;
2119 
2120         if ((*func)(dtp, dt_print_agg, &pd) == -1)
2121                 return (dt_set_errno(dtp, dtp->dt_errno));
2122 
2123         return (0);
2124 }
2125 
2126 void
2127 dtrace_aggregate_clear(dtrace_hdl_t *dtp)
2128 {
2129         dt_aggregate_t *agp = &dtp->dt_aggregate;
2130         dt_ahash_t *hash = &agp->dtat_hash;
2131         dt_ahashent_t *h;
2132         dtrace_aggdata_t *data;