001/*
002 * Copyright 2008-2019 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2015-2019 Ping Identity Corporation
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021package com.unboundid.ldap.sdk.unboundidds.monitors;
022
023
024
025import java.util.ArrayList;
026import java.util.Collections;
027import java.util.LinkedHashMap;
028import java.util.List;
029import java.util.Map;
030import java.util.TreeMap;
031import java.util.TreeSet;
032
033import com.unboundid.ldap.sdk.Attribute;
034import com.unboundid.ldap.sdk.Entry;
035import com.unboundid.util.Debug;
036import com.unboundid.util.NotMutable;
037import com.unboundid.util.StaticUtils;
038import com.unboundid.util.ThreadSafety;
039import com.unboundid.util.ThreadSafetyLevel;
040
041import static com.unboundid.ldap.sdk.unboundidds.monitors.MonitorMessages.*;
042
043
044
045/**
046 * This class defines a monitor entry that provides information about the memory
047 * usage for the JVM in which the Directory Server is running.  In particular,
048 * it reports information about the memory pools and garbage collectors defined
049 * in the JVM.
050 * <BR>
051 * <BLOCKQUOTE>
052 *   <B>NOTE:</B>  This class, and other classes within the
053 *   {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only
054 *   supported for use against Ping Identity, UnboundID, and
055 *   Nokia/Alcatel-Lucent 8661 server products.  These classes provide support
056 *   for proprietary functionality or for external specifications that are not
057 *   considered stable or mature enough to be guaranteed to work in an
058 *   interoperable way with other types of LDAP servers.
059 * </BLOCKQUOTE>
060 * <BR>
061 * The information that may be available in the memory usage monitor entry
062 * includes:
063 * <UL>
064 *   <LI>The names of the memory pools that are in use within the JVM.</LI>
065 *   <LI>The number of bytes currently used within each memory pool.</LI>
066 *   <LI>The number of bytes used within each memory pool after the last
067 *       garbage collection.</LI>
068 *   <LI>The names of the garbage collectors that are in use within the
069 *       JVM.</LI>
070 *   <LI>The number of garbage collections performed by each collector.</LI>
071 *   <LI>The total duration of all garbage collections performed by each
072 *       collector.</LI>
073 *   <LI>The average duration of garbage collections performed by each
074 *       collector.</LI>
075 *   <LI>The duration of the most recent garbage collection performed by each
076 *       collector.</LI>
077 *   <LI>The amount of non-heap memory consumed by the JVM.</LI>
078 *   <LI>The number of detected pauses of various durations detected by the
079 *       server.</LI>
080 *   <LI>The duration of the longest pause detected by the server.</LI>
081 * </UL>
082 * The server should present at most one memory usage monitor entry.  It can be
083 * retrieved using the {@link MonitorManager#getMemoryUsageMonitorEntry} method.
084 * This entry provides specific methods for accessing information about JVM
085 * memory usage (e.g., the {@link MemoryUsageMonitorEntry#getMemoryPoolNames}
086 * method can be used to retrieve the names of the memory pool).  Alternately,
087 * this information may be accessed using the generic API.  See the
088 * {@link MonitorManager} class documentation for an example that demonstrates
089 * the use of the generic API for accessing monitor data.
090 */
091@NotMutable()
092@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
093public final class MemoryUsageMonitorEntry
094       extends MonitorEntry
095{
096  /**
097   * The structural object class used in memory usage monitor entries.
098   */
099  static final String MEMORY_USAGE_MONITOR_OC =
100       "ds-memory-usage-monitor-entry";
101
102
103
104  /**
105   * The name of the attribute that holds the duration of the longest detected
106   * pause.
107   */
108  private static final String ATTR_LONGEST_PAUSE_TIME =
109       "max-detected-pause-time-millis";
110
111
112
113  /**
114   * The name of the attribute that holds the amount of non-heap memory used
115   * by the JVM.
116   */
117  private static final String ATTR_NON_HEAP_USED = "non-heap-memory-bytes-used";
118
119
120
121  /**
122   * The name of the attribute that holds the total amount of memory used by
123   * memory consumers.
124   */
125  private static final String ATTR_TOTAL_CONSUMER_MEMORY =
126       "total-bytes-used-by-memory-consumers";
127
128
129
130  /**
131   * The name of the attribute that holds the percentage of committed tenured
132   * memory held by memory consumers.
133   */
134  private static final String ATTR_TOTAL_CONSUMER_MEMORY_AS_PCT_OF_COMMITTED =
135       "memory-consumers-total-as-percent-of-committed-tenured-memory";
136
137
138
139  /**
140   * The name of the attribute that holds the percentage of maximum allowed
141   * tenured memory held by memory consumers.
142   */
143  private static final String ATTR_TOTAL_CONSUMER_MEMORY_AS_PCT_OF_MAX =
144       "memory-consumers-total-as-percent-of-maximum-tenured-memory";
145
146
147
148  /**
149   * The prefix that will be used for pauses detected by the server.
150   */
151  private static final String ATTR_PREFIX_DETECTED_PAUSE =
152       "detected-pauses-over-";
153
154
155
156  /**
157   * The suffix that will be used for attributes providing the total collection
158   * count for a garbage collector.
159   */
160  private static final String ATTR_SUFFIX_TOTAL_COLLECTION_COUNT =
161       "-total-collection-count";
162
163
164
165  /**
166   * The suffix that will be used for attributes providing the total collection
167   * duration for a garbage collector.
168   */
169  private static final String ATTR_SUFFIX_TOTAL_COLLECTION_DURATION =
170       "-total-collection-duration";
171
172
173
174  /**
175   * The suffix that will be used for attributes providing the average
176   * collection duration for a garbage collector.
177   */
178  private static final String ATTR_SUFFIX_AVERAGE_COLLECTION_DURATION =
179       "-average-collection-duration";
180
181
182
183  /**
184   * The suffix that will be used for attributes providing the recent collection
185   * duration for a garbage collector.
186   */
187  private static final String ATTR_SUFFIX_RECENT_COLLECTION_DURATION =
188       "-recent-collection-duration";
189
190
191
192  /**
193   * The suffix that will be used for attributes providing the current bytes
194   * used in a memory pool.
195   */
196  private static final String ATTR_SUFFIX_CURRENT_BYTES_USED =
197       "-current-bytes-used";
198
199
200
201  /**
202   * The suffix that will be used for attributes providing the bytes used after
203   * the last collection in a memory pool.
204   */
205  private static final String ATTR_SUFFIX_BYTES_USED_AFTER_LAST_COLLECTION =
206       "-bytes-used-after-last-collection";
207
208
209
210  /**
211   * The name of the property used to provide the numbers of pauses of various
212   * durations detected.
213   */
214  private static final String PROPERTY_DETECTED_PAUSE_COUNTS =
215       "detected-pause-counts";
216
217
218
219  /**
220   * The name of the attribute that holds the maximum amount of memory that may
221   * be used by the JVM, in megabytes.
222   */
223  private static final String ATTR_MAX_RESERVABLE_MEMORY_MB =
224       "maxReservableMemoryMB";
225
226
227
228  /**
229   * The name of the attribute that holds the amount of memory currently
230   * allocated for use by the JVM, in megabytes.
231   */
232  private static final String ATTR_CURRENT_RESERVED_MEMORY_MB =
233       "currentReservedMemoryMB";
234
235
236
237  /**
238   * The name of the attribute that holds the amount of allocated JVM memory
239   * which is actually in use.
240   */
241  private static final String ATTR_USED_MEMORY_MB = "usedReservedMemoryMB";
242
243
244
245  /**
246   * The name of the attribute that holds the amount of allocated JVM memory
247   * that is not currently in use.
248   */
249  private static final String ATTR_FREE_MEMORY_MB = "freeReservedMemoryMB";
250
251
252
253  /**
254   * The name of the attribute that holds the percentage of the maximum JVM
255   * memory that is actually in use.
256   */
257  private static final String ATTR_RESERVED_MEMORY_PERCENT_FULL =
258       "reservedMemoryPercentFull";
259
260
261
262  /**
263   * The serial version UID for this serializable class.
264   */
265  private static final long serialVersionUID = 1924052253885937441L;
266
267
268
269  // The list of garbage collectors for which information is available.
270  private final List<String> garbageCollectors;
271
272  // The list of memory pools for which information is available.
273  private final List<String> memoryPools;
274
275  // The amount of memory that has currently been allocated by the JVM, in
276  // megabytes.
277  private final Long currentReservedMemoryMB;
278
279  // The amount of allocated JVM memory that is not currently in use, in
280  // megabytes.
281  private final Long freeReservedMemoryMB;
282
283  // The maximum pause time detected by the JVM.
284  private final Long maxDetectedPauseTime;
285
286  // The maximum amount of memory that may be used by the JVM, in megabytes.
287  private final Long maxReservableMemoryMB;
288
289  // The amount of non-heap memory consumed by the JVM.
290  private final Long nonHeapMemoryUsed;
291
292  // The percentage of committed tenured memory held by consumers.
293  private final Long percentOfCommittedTenuredMemory;
294
295  // The percentage of maximum tenured memory held by consumers.
296  private final Long percentOfMaxTenuredMemory;
297
298  // The percentage of the maximum JVM memory that is currently in use.
299  private final Long reservedMemoryPercentFull;
300
301  // The total amount of memory held by memory consumers.
302  private final Long totalBytesHeldByConsumers;
303
304  // The amount of allocated JVM memory that is currently in use, in megabytes.
305  private final Long usedReservedMemoryMB;
306
307  // The number of pauses exceeding specified thresholds.
308  private final Map<Long,Long> detectedPauses;
309
310  // The list of bytes used after the last collection per memory pool.
311  private final Map<String,Long> bytesUsedAfterLastCollectionPerMP;
312
313  // The list of current bytes used per memory pool.
314  private final Map<String,Long> currentBytesUsedPerMP;
315
316  // The list of average collection durations per garbage collector.
317  private final Map<String,Long> averageCollectionDurationPerGC;
318
319  // The list of recent collection durations per garbage collector.
320  private final Map<String,Long> recentCollectionDurationPerGC;
321
322  // The list of total collection counts per garbage collector.
323  private final Map<String,Long> totalCollectionCountPerGC;
324
325  // The list of total collection durations per garbage collector.
326  private final Map<String,Long> totalCollectionDurationPerGC;
327
328
329
330  /**
331   * Creates a new memory usage monitor entry from the provided entry.
332   *
333   * @param  entry  The entry to be parsed as a memory usage monitor entry.  It
334   *                must not be {@code null}.
335   */
336  public MemoryUsageMonitorEntry(final Entry entry)
337  {
338    super(entry);
339
340    maxDetectedPauseTime            = getLong(ATTR_LONGEST_PAUSE_TIME);
341    nonHeapMemoryUsed               = getLong(ATTR_NON_HEAP_USED);
342    totalBytesHeldByConsumers       = getLong(ATTR_TOTAL_CONSUMER_MEMORY);
343    percentOfCommittedTenuredMemory =
344         getLong(ATTR_TOTAL_CONSUMER_MEMORY_AS_PCT_OF_COMMITTED);
345    percentOfMaxTenuredMemory =
346         getLong(ATTR_TOTAL_CONSUMER_MEMORY_AS_PCT_OF_MAX);
347
348    maxReservableMemoryMB     = getLong(ATTR_MAX_RESERVABLE_MEMORY_MB);
349    currentReservedMemoryMB   = getLong(ATTR_CURRENT_RESERVED_MEMORY_MB);
350    usedReservedMemoryMB      = getLong(ATTR_USED_MEMORY_MB);
351    freeReservedMemoryMB      = getLong(ATTR_FREE_MEMORY_MB);
352    reservedMemoryPercentFull = getLong(ATTR_RESERVED_MEMORY_PERCENT_FULL);
353
354
355    final TreeMap<Long,Long> pauses = new TreeMap<>();
356
357    final TreeSet<String> mpNames = new TreeSet<>();
358    final TreeSet<String> gcNames = new TreeSet<>();
359
360    final TreeMap<String,Long> averageDurations = new TreeMap<>();
361    final TreeMap<String,Long> currentBytesUsed = new TreeMap<>();
362    final TreeMap<String,Long> lastBytesUsed    = new TreeMap<>();
363    final TreeMap<String,Long> recentDurations  = new TreeMap<>();
364    final TreeMap<String,Long> totalCounts      = new TreeMap<>();
365    final TreeMap<String,Long> totalDurations   = new TreeMap<>();
366
367    for (final Attribute a : entry.getAttributes())
368    {
369      final String name      = a.getName();
370      final String lowerName = StaticUtils.toLowerCase(name);
371
372      if (lowerName.startsWith(ATTR_PREFIX_DETECTED_PAUSE))
373      {
374        final Long l = getLong(name);
375
376        final String timeStr =
377             lowerName.substring(ATTR_PREFIX_DETECTED_PAUSE.length());
378        if (timeStr.endsWith("ms"))
379        {
380          try
381          {
382            final long millis =
383                 Long.parseLong(timeStr.substring(0, timeStr.length()-2));
384            pauses.put(millis, l);
385          }
386          catch (final Exception e)
387          {
388            Debug.debugException(e);
389          }
390        }
391        else if (timeStr.endsWith("s"))
392        {
393          try
394          {
395            final long millis = 1000 *
396                 Long.parseLong(timeStr.substring(0, timeStr.length()-1));
397            pauses.put(millis, l);
398          }
399          catch (final Exception e)
400          {
401            Debug.debugException(e);
402          }
403        }
404      }
405
406      int pos = lowerName.indexOf(ATTR_SUFFIX_AVERAGE_COLLECTION_DURATION);
407      if (pos > 0)
408      {
409        final String gcName = name.substring(0, pos);
410        gcNames.add(gcName);
411
412        final Long l = getLong(name);
413        if (l != null)
414        {
415          averageDurations.put(StaticUtils.toLowerCase(gcName), l);
416        }
417
418        continue;
419      }
420
421      pos = lowerName.indexOf(ATTR_SUFFIX_BYTES_USED_AFTER_LAST_COLLECTION);
422      if (pos > 0)
423      {
424        final String mpName = name.substring(0, pos);
425        mpNames.add(mpName);
426
427        final Long l = getLong(name);
428        if (l != null)
429        {
430          lastBytesUsed.put(StaticUtils.toLowerCase(mpName), l);
431        }
432
433        continue;
434      }
435
436      pos = lowerName.indexOf(ATTR_SUFFIX_CURRENT_BYTES_USED);
437      if (pos > 0)
438      {
439        final String mpName = name.substring(0, pos);
440        mpNames.add(mpName);
441
442        final Long l = getLong(name);
443        if (l != null)
444        {
445          currentBytesUsed.put(StaticUtils.toLowerCase(mpName), l);
446        }
447
448        continue;
449      }
450
451      pos = lowerName.indexOf(ATTR_SUFFIX_RECENT_COLLECTION_DURATION);
452      if (pos > 0)
453      {
454        final String gcName = name.substring(0, pos);
455        gcNames.add(gcName);
456
457        final Long l = getLong(name);
458        if (l != null)
459        {
460          recentDurations.put(StaticUtils.toLowerCase(gcName), l);
461        }
462
463        continue;
464      }
465
466      pos = lowerName.indexOf(ATTR_SUFFIX_TOTAL_COLLECTION_COUNT);
467      if ((pos > 0) && (! lowerName.startsWith("mem-pool-")))
468      {
469        final String gcName = name.substring(0, pos);
470        gcNames.add(gcName);
471
472        final Long l = getLong(name);
473        if (l != null)
474        {
475          totalCounts.put(StaticUtils.toLowerCase(gcName), l);
476        }
477
478        continue;
479      }
480
481      pos = lowerName.indexOf(ATTR_SUFFIX_TOTAL_COLLECTION_DURATION);
482      if (pos > 0)
483      {
484        final String gcName = name.substring(0, pos);
485        gcNames.add(gcName);
486
487        final Long l = getLong(name);
488        if (l != null)
489        {
490          totalDurations.put(StaticUtils.toLowerCase(gcName), l);
491        }
492
493        continue;
494      }
495    }
496
497
498    garbageCollectors =
499         Collections.unmodifiableList(new ArrayList<>(gcNames));
500
501    memoryPools = Collections.unmodifiableList(new ArrayList<>(mpNames));
502
503    totalCollectionCountPerGC = Collections.unmodifiableMap(totalCounts);
504
505    totalCollectionDurationPerGC = Collections.unmodifiableMap(totalDurations);
506
507    averageCollectionDurationPerGC =
508         Collections.unmodifiableMap(averageDurations);
509
510    recentCollectionDurationPerGC =
511         Collections.unmodifiableMap(recentDurations);
512
513    bytesUsedAfterLastCollectionPerMP =
514         Collections.unmodifiableMap(lastBytesUsed);
515
516    currentBytesUsedPerMP = Collections.unmodifiableMap(currentBytesUsed);
517
518    detectedPauses = Collections.unmodifiableMap(pauses);
519  }
520
521
522
523  /**
524   * Retrieves the maximum amount of memory (in megabytes) that may be allocated
525   * and used by the JVM.
526   *
527   * @return  The maximum amount of memory (in megabytes) that may be allocated
528   *          and used by the JVM, or {@code null} if this was not included in
529   *          the monitor entry.
530   */
531  public Long getMaxReservableMemoryMB()
532  {
533    return maxReservableMemoryMB;
534  }
535
536
537
538  /**
539   * Retrieves the amount of memory (in megabytes) that is currently allocated
540   * for use by the JVM.
541   *
542   * @return  The amount of memory (in megabytes) that is currently allocated
543   *          for use by the JVM, or {@code null} if this was not included in
544   *          the monitor entry.
545   */
546  public Long getCurrentReservedMemoryMB()
547  {
548    return currentReservedMemoryMB;
549  }
550
551
552
553  /**
554   * Retrieves the amount of memory (in megabytes) allocated for use by the JVM
555   * that is currently in use for holding Java objects.
556   *
557   * @return  The amount of memory (in megabytes) allocated for use by the JVM
558   *          that is currently in use for holding Java objects, or {@code null}
559   *          if this was not included in the monitor entry.
560   */
561  public Long getUsedReservedMemoryMB()
562  {
563    return usedReservedMemoryMB;
564  }
565
566
567
568  /**
569   * Retrieves the amount of memory (in megabytes) allocated for use by the JVM
570   * that is not currently in use for holding Java objects.
571   *
572   * @return  The amount of memory (in megabytes) allocated for use by the JVM
573   *          that is not currently in use for holding Java objects, or
574   *          {@code null} if this was not included in the monitor entry.
575   */
576  public Long getFreeReservedMemoryMB()
577  {
578    return freeReservedMemoryMB;
579  }
580
581
582
583  /**
584   * Retrieves the percent of the currently-reserved memory that is actually in
585   * use by the JVM for storing Java objects.
586   *
587   * @return  The percent of the currently-reserved memory that is actually in
588   *          use by the JVM for storing Java objects.
589   */
590  public Long getReservedMemoryPercentFull()
591  {
592    return reservedMemoryPercentFull;
593  }
594
595
596
597  /**
598   * Retrieves the names of the garbage collectors for which information is
599   * available.
600   *
601   * @return  The names of the garbage collectors for which information is
602   *          available.
603   */
604  public List<String> getGarbageCollectorNames()
605  {
606    return garbageCollectors;
607  }
608
609
610
611  /**
612   * Retrieves the names of the memory pools for which information is available.
613   *
614   * @return  The names of the memory pools for which information is available.
615   */
616  public List<String> getMemoryPoolNames()
617  {
618    return memoryPools;
619  }
620
621
622
623  /**
624   * Retrieves a map containing the total number of garbage collections
625   * performed per collector.
626   *
627   * @return  A map containing the total number of garbage collections performed
628   *          per collector.
629   */
630  public Map<String,Long> getTotalCollectionCounts()
631  {
632    return totalCollectionCountPerGC;
633  }
634
635
636
637  /**
638   * Retrieves the total number of garbage collections performed by the
639   * specified collector.
640   *
641   * @param  collectorName  The name of the garbage collector for which to
642   *                        retrieve the information.
643   *
644   * @return  The total number of garbage collections performed by the specified
645   *          collector, or {@code null} if that information is not available.
646   */
647  public Long getTotalCollectionCount(final String collectorName)
648  {
649    return totalCollectionCountPerGC.get(
650         StaticUtils.toLowerCase(collectorName));
651  }
652
653
654
655  /**
656   * Retrieves a map containing the total length of time (in milliseconds) spent
657   * performing garbage collection per collector.
658   *
659   * @return  A map containing the total length of time (in milliseconds) spent
660   *          performing garbage collection per collector.
661   */
662  public Map<String,Long> getTotalCollectionDurations()
663  {
664    return totalCollectionDurationPerGC;
665  }
666
667
668
669  /**
670   * Retrieves the total length of time (in milliseconds) spent performing
671   * garbage collection for the specified collector.
672   *
673   * @param  collectorName  The name of the garbage collector for which to
674   *                        retrieve the information.
675   *
676   * @return  The total length of time (in milliseconds) spent performing
677   *          garbage collection for the specified collector, or {@code null} if
678   *          that information is not available.
679   */
680  public Long getTotalCollectionDuration(final String collectorName)
681  {
682    return totalCollectionDurationPerGC.get(
683         StaticUtils.toLowerCase(collectorName));
684  }
685
686
687
688  /**
689   * Retrieves a map containing the average garbage collection duration (in
690   * milliseconds) per garbage collector.
691   *
692   * @return  A map containing the average garbage collection duration (in
693   *          milliseconds) per garbage collector.
694   */
695  public Map<String,Long> getAverageCollectionDurations()
696  {
697    return averageCollectionDurationPerGC;
698  }
699
700
701
702  /**
703   * Retrieves the average garbage collection duration (in milliseconds) for the
704   * specified collector.
705   *
706   * @param  collectorName  The name of the garbage collector for which to
707   *                        retrieve the information.
708   *
709   * @return  The average garbage collection duration (in milliseconds) for the
710   *          specified collector, or {@code null} if that information is not
711   *          available.
712   */
713  public Long getAverageCollectionDuration(final String collectorName)
714  {
715    return averageCollectionDurationPerGC.get(
716         StaticUtils.toLowerCase(collectorName));
717  }
718
719
720
721  /**
722   * Retrieves a map containing the most recent garbage collection duration (in
723   * milliseconds) per garbage collector.
724   *
725   * @return  A map containing the duration of the most recent garbage
726   *          collection duration (in milliseconds) per garbage collector.
727   */
728  public Map<String,Long> getRecentCollectionDurations()
729  {
730    return recentCollectionDurationPerGC;
731  }
732
733
734
735  /**
736   * Retrieves the duration (in milliseconds) of the most recent garbage
737   * collection for the specified collector.
738   *
739   * @param  collectorName  The name of the garbage collector for which to
740   *                        retrieve the information.
741   *
742   * @return  The duration (in milliseconds) of the most recent garbage
743   *          collection for the specified collector, or {@code null} if that
744   *          information is not available.
745   */
746  public Long getRecentCollectionDuration(final String collectorName)
747  {
748    return recentCollectionDurationPerGC.get(
749         StaticUtils.toLowerCase(collectorName));
750  }
751
752
753
754  /**
755   * Retrieves a map containing the current number of bytes used per memory
756   * pool.
757   *
758   * @return  A map containing the current number of bytes used per memory pool.
759   */
760  public Map<String,Long> getCurrentBytesUsed()
761  {
762    return currentBytesUsedPerMP;
763  }
764
765
766
767  /**
768   * Retrieves the current number of bytes used for the specified memory pool.
769   *
770   * @param  poolName  The name of the memory pool for which to retrieve the
771   *                   information.
772   *
773   * @return  The current number of bytes used for the specified memory pool, or
774   *          {@code null} if that information is not available.
775   */
776  public Long getCurrentBytesUsed(final String poolName)
777  {
778    return currentBytesUsedPerMP.get(StaticUtils.toLowerCase(poolName));
779  }
780
781
782
783  /**
784   * Retrieves a map containing the number of bytes used after the last garbage
785   * collection per memory pool.
786   *
787   * @return  A map containing the number of bytes used after the last garbage
788   *          collection per memory pool.
789   */
790  public Map<String,Long> getBytesUsedAfterLastCollection()
791  {
792    return bytesUsedAfterLastCollectionPerMP;
793  }
794
795
796
797  /**
798   * Retrieves the number of bytes used after the last garbage collection for
799   * the specified memory pool.
800   *
801   * @param  poolName  The name of the memory pool for which to retrieve the
802   *                   information.
803   *
804   * @return  The number of bytes used after the last garbage collection for the
805   *          specified memory pool, or {@code null} if that information is not
806   *          available.
807   */
808  public Long getBytesUsedAfterLastCollection(final String poolName)
809  {
810    return bytesUsedAfterLastCollectionPerMP.get(
811         StaticUtils.toLowerCase(poolName));
812  }
813
814
815
816  /**
817   * Retrieves the amount of non-heap memory consumed by the JVM.
818   *
819   * @return  The amount of non-heap memory consumed by the JVM, or {@code null}
820   *          if that information is not available.
821   */
822  public Long getNonHeapMemoryBytesUsed()
823  {
824    return nonHeapMemoryUsed;
825  }
826
827
828
829  /**
830   * Retrieves the total amount of memory in bytes held by memory consumers.
831   *
832   * @return  The total amount of memory in bytes held by memory consumers, or
833   *          {@code null} if that information is not available.
834   */
835  public Long getTotalBytesUsedByMemoryConsumers()
836  {
837    return totalBytesHeldByConsumers;
838  }
839
840
841
842  /**
843   * Retrieves the percentage of the maximum allowed amount of tenured memory
844   * that is used by memory consumers (assuming that all memory used by memory
845   * consumers is contained in the tenured generation).
846   *
847   * @return  The percentage of the maximum allowed amount of tenured memory
848   *          that is used by memory consumers, or {@code null} if that
849   *          information is not available.
850   */
851  public Long getPercentageOfMaximumTenuredMemoryUsedByMemoryConsumers()
852  {
853    return percentOfMaxTenuredMemory;
854  }
855
856
857
858  /**
859   * Retrieves the percentage of the committed amount of tenured memory that is
860   * used by memory consumers (assuming that all memory used by memory consumers
861   * is contained in the tenured generation).
862   *
863   * @return  The percentage of the committed amount of tenured memory that is
864   *          used by memory consumers, or {@code null} if that information is
865   *          not available.
866   */
867  public Long getPercentageOfCommittedTenuredMemoryUsedByMemoryConsumers()
868  {
869    return percentOfCommittedTenuredMemory;
870  }
871
872
873
874  /**
875   * Retrieves the number of pauses of various durations detected by the server.
876   * The value returned will contain a map between the minimum duration in
877   * milliseconds for the associated bucket and the number of pauses detected of
878   * at least that duration.
879   *
880   * @return  The number of pauses of various durations detected by the server.
881   */
882  public Map<Long,Long> getDetectedPauseCounts()
883  {
884    return detectedPauses;
885  }
886
887
888
889  /**
890   * Retrieves the duration of the longest pause detected by the server.
891   *
892   * @return  The duration of the longest pause detected by the server, or
893   *          {@code null} if that information is not available.
894   */
895  public Long getMaxDetectedPauseTimeMillis()
896  {
897    return maxDetectedPauseTime;
898  }
899
900
901
902  /**
903   * {@inheritDoc}
904   */
905  @Override()
906  public String getMonitorDisplayName()
907  {
908    return INFO_MEMORY_USAGE_MONITOR_DISPNAME.get();
909  }
910
911
912
913  /**
914   * {@inheritDoc}
915   */
916  @Override()
917  public String getMonitorDescription()
918  {
919    return INFO_MEMORY_USAGE_MONITOR_DESC.get();
920  }
921
922
923
924  /**
925   * {@inheritDoc}
926   */
927  @Override()
928  public Map<String,MonitorAttribute> getMonitorAttributes()
929  {
930    final LinkedHashMap<String,MonitorAttribute> attrs =
931         new LinkedHashMap<>(StaticUtils.computeMapCapacity(50));
932
933    if (maxReservableMemoryMB != null)
934    {
935      addMonitorAttribute(attrs,
936           ATTR_MAX_RESERVABLE_MEMORY_MB,
937           INFO_MEMORY_USAGE_DISPNAME_MAX_MEM.get(),
938           INFO_MEMORY_USAGE_DESC_MAX_MEM.get(),
939           maxReservableMemoryMB);
940    }
941
942    if (currentReservedMemoryMB != null)
943    {
944      addMonitorAttribute(attrs,
945           ATTR_CURRENT_RESERVED_MEMORY_MB,
946           INFO_MEMORY_USAGE_DISPNAME_CURRENT_MEM.get(),
947           INFO_MEMORY_USAGE_DESC_CURRENT_MEM.get(),
948           currentReservedMemoryMB);
949    }
950
951    if (usedReservedMemoryMB != null)
952    {
953      addMonitorAttribute(attrs,
954           ATTR_USED_MEMORY_MB,
955           INFO_MEMORY_USAGE_DISPNAME_USED_MEM.get(),
956           INFO_MEMORY_USAGE_DESC_USED_MEM.get(),
957           usedReservedMemoryMB);
958    }
959
960    if (freeReservedMemoryMB != null)
961    {
962      addMonitorAttribute(attrs,
963           ATTR_FREE_MEMORY_MB,
964           INFO_MEMORY_USAGE_DISPNAME_FREE_MEM.get(),
965           INFO_MEMORY_USAGE_DESC_FREE_MEM.get(),
966           freeReservedMemoryMB);
967    }
968
969    if (reservedMemoryPercentFull != null)
970    {
971      addMonitorAttribute(attrs,
972           ATTR_RESERVED_MEMORY_PERCENT_FULL,
973           INFO_MEMORY_USAGE_DISPNAME_RESERVED_PCT.get(),
974           INFO_MEMORY_USAGE_DESC_RESERVED_PCT.get(),
975           reservedMemoryPercentFull);
976    }
977
978    if (! garbageCollectors.isEmpty())
979    {
980      addMonitorAttribute(attrs,
981           "gcNames",
982           INFO_MEMORY_USAGE_DISPNAME_GC_NAMES.get(),
983           INFO_MEMORY_USAGE_DESC_GC_NAMES.get(),
984           garbageCollectors);
985    }
986
987    if (! totalCollectionCountPerGC.isEmpty())
988    {
989      for (final String name : totalCollectionCountPerGC.keySet())
990      {
991        addMonitorAttribute(attrs,
992            "totalCollectionCount-" + name,
993            INFO_MEMORY_USAGE_DISPNAME_TOTAL_COLLECTION_COUNT.get(name),
994            INFO_MEMORY_USAGE_DESC_TOTAL_COLLECTION_COUNT.get(name),
995            totalCollectionCountPerGC.get(name));
996      }
997    }
998
999    if (! totalCollectionDurationPerGC.isEmpty())
1000    {
1001      for (final String name : totalCollectionDurationPerGC.keySet())
1002      {
1003        addMonitorAttribute(attrs,
1004            "totalCollectionDuration-" + name,
1005            INFO_MEMORY_USAGE_DISPNAME_TOTAL_COLLECTION_DURATION.get(name),
1006            INFO_MEMORY_USAGE_DESC_TOTAL_COLLECTION_DURATION.get(name),
1007            totalCollectionDurationPerGC.get(name));
1008      }
1009    }
1010
1011    if (! averageCollectionDurationPerGC.isEmpty())
1012    {
1013      for (final String name : averageCollectionDurationPerGC.keySet())
1014      {
1015        addMonitorAttribute(attrs,
1016            "averageCollectionDuration-" + name,
1017            INFO_MEMORY_USAGE_DISPNAME_AVERAGE_COLLECTION_DURATION.get(name),
1018            INFO_MEMORY_USAGE_DESC_AVERAGE_COLLECTION_DURATION.get(name),
1019            averageCollectionDurationPerGC.get(name));
1020      }
1021    }
1022
1023    if (! recentCollectionDurationPerGC.isEmpty())
1024    {
1025      for (final String name : recentCollectionDurationPerGC.keySet())
1026      {
1027        addMonitorAttribute(attrs,
1028            "recentCollectionDuration-" + name,
1029            INFO_MEMORY_USAGE_DISPNAME_RECENT_COLLECTION_DURATION.get(name),
1030            INFO_MEMORY_USAGE_DESC_RECENT_COLLECTION_DURATION.get(name),
1031            recentCollectionDurationPerGC.get(name));
1032      }
1033    }
1034
1035    if (! memoryPools.isEmpty())
1036    {
1037      addMonitorAttribute(attrs,
1038           "memoryPools",
1039           INFO_MEMORY_USAGE_DISPNAME_MEMORY_POOLS.get(),
1040           INFO_MEMORY_USAGE_DESC_MEMORY_POOLS.get(),
1041           memoryPools);
1042    }
1043
1044    if (! currentBytesUsedPerMP.isEmpty())
1045    {
1046      for (final String name : currentBytesUsedPerMP.keySet())
1047      {
1048        addMonitorAttribute(attrs,
1049            "currentBytesUsed-" + name,
1050            INFO_MEMORY_USAGE_DISPNAME_CURRENT_BYTES_USED.get(name),
1051            INFO_MEMORY_USAGE_DESC_CURRENT_BYTES_USED.get(name),
1052            currentBytesUsedPerMP.get(name));
1053      }
1054    }
1055
1056    if (! bytesUsedAfterLastCollectionPerMP.isEmpty())
1057    {
1058      for (final String name : bytesUsedAfterLastCollectionPerMP.keySet())
1059      {
1060        addMonitorAttribute(attrs,
1061            "bytesUsedAfterLastCollection-" + name,
1062            INFO_MEMORY_USAGE_DISPNAME_BYTES_USED_AFTER_COLLECTION.get(name),
1063            INFO_MEMORY_USAGE_DESC_BYTES_USED_AFTER_COLLECTION.get(name),
1064            bytesUsedAfterLastCollectionPerMP.get(name));
1065      }
1066    }
1067
1068    if (nonHeapMemoryUsed != null)
1069    {
1070      addMonitorAttribute(attrs,
1071           ATTR_NON_HEAP_USED,
1072           INFO_MEMORY_USAGE_DISPNAME_NON_HEAP_MEMORY.get(),
1073           INFO_MEMORY_USAGE_DESC_NON_HEAP_MEMORY.get(),
1074           nonHeapMemoryUsed);
1075    }
1076
1077    if (totalBytesHeldByConsumers != null)
1078    {
1079      addMonitorAttribute(attrs,
1080           ATTR_TOTAL_CONSUMER_MEMORY,
1081           INFO_MEMORY_USAGE_DISPNAME_TOTAL_CONSUMER_MEMORY.get(),
1082           INFO_MEMORY_USAGE_DESC_TOTAL_CONSUMER_MEMORY.get(),
1083           totalBytesHeldByConsumers);
1084    }
1085
1086    if (percentOfMaxTenuredMemory != null)
1087    {
1088      addMonitorAttribute(attrs,
1089           ATTR_TOTAL_CONSUMER_MEMORY_AS_PCT_OF_MAX,
1090           INFO_MEMORY_USAGE_DISPNAME_CONSUMERS_AS_PCT_OF_MAX.get(),
1091           INFO_MEMORY_USAGE_DESC_CONSUMERS_AS_PCT_OF_MAX.get(),
1092           percentOfMaxTenuredMemory);
1093    }
1094
1095    if (percentOfCommittedTenuredMemory != null)
1096    {
1097      addMonitorAttribute(attrs,
1098           ATTR_TOTAL_CONSUMER_MEMORY_AS_PCT_OF_COMMITTED,
1099           INFO_MEMORY_USAGE_DISPNAME_CONSUMERS_AS_PCT_OF_COMMITTED.get(),
1100           INFO_MEMORY_USAGE_DESC_CONSUMERS_AS_PCT_OF_COMMITTED.get(),
1101           percentOfCommittedTenuredMemory);
1102    }
1103
1104    if (! detectedPauses.isEmpty())
1105    {
1106      final ArrayList<String> values =
1107           new ArrayList<>(detectedPauses.size());
1108      for (final Map.Entry<Long,Long> e : detectedPauses.entrySet())
1109      {
1110        values.add(e.getKey() + "ms=" + e.getValue());
1111      }
1112
1113      addMonitorAttribute(attrs,
1114           PROPERTY_DETECTED_PAUSE_COUNTS,
1115           INFO_MEMORY_USAGE_DISPNAME_DETECTED_PAUSES.get(),
1116           INFO_MEMORY_USAGE_DESC_DETECTED_PAUSES.get(),
1117           values);
1118    }
1119
1120    if (maxDetectedPauseTime != null)
1121    {
1122      addMonitorAttribute(attrs,
1123           ATTR_LONGEST_PAUSE_TIME,
1124           INFO_MEMORY_USAGE_DISPNAME_MAX_PAUSE_TIME.get(),
1125           INFO_MEMORY_USAGE_DESC_MAX_PAUSE_TIME.get(),
1126           maxDetectedPauseTime);
1127    }
1128
1129    return Collections.unmodifiableMap(attrs);
1130  }
1131}