784 total += value |
784 total += value |
785 except TypeError: |
785 except TypeError: |
786 LOG.error(_("Unable to aggregate non-summable kstat %s;%s " |
786 LOG.error(_("Unable to aggregate non-summable kstat %s;%s " |
787 " of type %s") % (ks.getParent().uri, statistic, |
787 " of type %s") % (ks.getParent().uri, statistic, |
788 type(value))) |
788 type(value))) |
789 return None |
789 return 0 |
790 |
790 |
791 return total |
791 return total |
792 |
792 |
793 def _get_kstat_statistic(self, ks, statistic): |
793 def _get_kstat_statistic(self, ks, statistic): |
794 if not isinstance(ks, kstat.Kstat): |
794 if not isinstance(ks, kstat.Kstat): |
803 |
803 |
804 return value |
804 return value |
805 |
805 |
806 def _get_cpu_time(self, zone): |
806 def _get_cpu_time(self, zone): |
807 """Return the CPU time used in nanoseconds.""" |
807 """Return the CPU time used in nanoseconds.""" |
808 if zone.name is None: |
808 # If the zone is not in a running state, the information requested |
|
809 # cannot be gathered, so simply return 0. |
|
810 if zone.name is None or zone.state != ZONE_STATE_RUNNING: |
809 return 0 |
811 return 0 |
810 |
812 |
811 # Loop over the kstats for each cpu. If the cpu list changes, the |
813 # Loop over the kstats for each cpu. If the cpu list changes, the |
812 # gen_num for the accumulated kstat will change invalidating the |
814 # gen_num for the accumulated kstat will change invalidating the |
813 # result, so retry if this happens. |
815 # result, so retry if this happens. |
814 # The retry value of 3 was determined by the "we shouldn't hit this |
816 # The retry value of 3 was determined by the "we shouldn't hit this |
815 # often, but if we do it should resolve quickly so try again"+1 |
817 # often, but if we do it should resolve quickly so try again"+1 |
816 # algorithm. |
818 # algorithm. |
|
819 uri = "kstat:/zones/%s/cpu" % zone.name |
|
820 accum_uri = "kstat:/zones/%s/cpu/accum/sys" % zone.name |
817 for _attempt in range(3): |
821 for _attempt in range(3): |
818 total = 0 |
822 total = 0 |
819 |
823 |
820 uri = "kstat:/zones/%s/cpu" % zone.name |
|
821 accum_uri = "kstat:/zones/%s/cpu/accum/sys" % zone.name |
|
822 |
|
823 initial = self._kstat_data(accum_uri) |
824 initial = self._kstat_data(accum_uri) |
824 cpus = self._kstat_data(uri) |
825 cpus = self._kstat_data(uri) |
|
826 if cpus is None: |
|
827 # If the zone state is not running then give up but if it is |
|
828 # running try again. |
|
829 if zone.state != ZONE_STATE_RUNNING: |
|
830 break |
|
831 else: |
|
832 continue |
825 cpus.pop('pset_accum') |
833 cpus.pop('pset_accum') |
826 cpus.pop('accum') |
834 cpus.pop('accum') |
827 |
835 |
828 for n in cpus.keys(): |
836 cpu = None |
|
837 for n in cpus: |
829 cpu = self._kstat_data(uri + "/%s" % n) |
838 cpu = self._kstat_data(uri + "/%s" % n) |
|
839 if cpu is None: |
|
840 if zone.state != ZONE_STATE_RUNNING: |
|
841 return 0 |
|
842 else: |
|
843 break |
830 |
844 |
831 total += self._sum_kstat_statistic(cpu, 'cpu_nsec_kernel_cur') |
845 total += self._sum_kstat_statistic(cpu, 'cpu_nsec_kernel_cur') |
832 total += self._sum_kstat_statistic(cpu, 'cpu_nsec_user_cur') |
846 total += self._sum_kstat_statistic(cpu, 'cpu_nsec_user_cur') |
833 |
847 |
|
848 if cpu is None: |
|
849 continue |
|
850 |
834 final = self._kstat_data(accum_uri) |
851 final = self._kstat_data(accum_uri) |
|
852 if final is None: |
|
853 continue |
835 |
854 |
836 if initial['gen_num'] == final['gen_num']: |
855 if initial['gen_num'] == final['gen_num']: |
837 total += initial['cpu_nsec_user'] + initial['cpu_nsec_kernel'] |
856 total += initial['cpu_nsec_user'] + initial['cpu_nsec_kernel'] |
838 return total |
857 return total |
839 |
858 |
2691 """ |
2710 """ |
2692 raise NotImplementedError() |
2711 raise NotImplementedError() |
2693 |
2712 |
2694 def _get_zone_diagnostics(self, zone): |
2713 def _get_zone_diagnostics(self, zone): |
2695 """Return data about Solaris Zone diagnostics.""" |
2714 """Return data about Solaris Zone diagnostics.""" |
2696 if zone.id == -1: |
2715 if zone.name is None or zone.state != ZONE_STATE_RUNNING: |
2697 return None |
2716 return None |
2698 |
2717 |
2699 diagnostics = defaultdict(lambda: 0) |
2718 diagnostics = defaultdict(lambda: 0) |
2700 |
2719 |
2701 for stat in ['lockedmem', 'nprocs', 'swapresv']: |
2720 for stat in ['lockedmem', 'nprocs', 'swapresv']: |
2712 uri = "kstat:/zones/%s/cpu" % zone.name |
2731 uri = "kstat:/zones/%s/cpu" % zone.name |
2713 accum_uri = "kstat:/zones/%s/cpu/accum/sys" % zone.name |
2732 accum_uri = "kstat:/zones/%s/cpu/accum/sys" % zone.name |
2714 |
2733 |
2715 for _attempt in range(3): |
2734 for _attempt in range(3): |
2716 initial = self._kstat_data(accum_uri) |
2735 initial = self._kstat_data(accum_uri) |
2717 data = self._kstat_data(uri) |
2736 cpus = self._kstat_data(uri) |
2718 data.pop('accum') |
2737 # Something went wrong in the data collection, if the zone is no |
2719 data.pop('pset_accum') |
2738 # longer running simply return None otherwise continue |
|
2739 if cpus is None: |
|
2740 if zone.state != ZONE_STATE_RUNNING: |
|
2741 return None |
|
2742 continue |
|
2743 cpus.pop('accum') |
|
2744 cpus.pop('pset_accum') |
2720 |
2745 |
2721 # Turn the list of cpu ids in data.keys into a dictionary of the |
2746 # Turn the list of cpu ids in data.keys into a dictionary of the |
2722 # 'sys' kstat for each cpu id. |
2747 # 'sys' kstat for each cpu id. |
2723 data = {n: self._kstat_data(uri + "/%s" % n)['sys'] |
2748 data = {} |
2724 for n in data.keys()} |
2749 datapoint = None |
|
2750 for n in cpus: |
|
2751 datapoint = self._kstat_data(uri + "/%s" % n) |
|
2752 # We could not get a datapoint for one of the cpus, so try the |
|
2753 # whole thing again if zone.state is still running. |
|
2754 if datapoint is None: |
|
2755 if zone.state != ZONE_STATE_RUNNING: |
|
2756 return None |
|
2757 else: |
|
2758 break |
|
2759 |
|
2760 data.update({n: datapoint['sys']}) |
|
2761 |
|
2762 if datapoint is None: |
|
2763 continue |
2725 |
2764 |
2726 # The list of cpu kstats in data must contain at least one element |
2765 # The list of cpu kstats in data must contain at least one element |
2727 # and all elements have the same map of statistics, since they're |
2766 # and all elements have the same map of statistics, since they're |
2728 # all the same kstat type. This gets a list of all the statistics |
2767 # all the same kstat type. This gets a list of all the statistics |
2729 # which end in "_cur" from the first (guaranteed) kstat element. |
2768 # which end in "_cur" from the first (guaranteed) kstat element. |