Merge branch 'collectd-5.5'
authorRuben Kerkhof <ruben@rubenkerkhof.com>
Tue, 10 May 2016 09:53:28 +0000 (11:53 +0200)
committerRuben Kerkhof <ruben@rubenkerkhof.com>
Tue, 10 May 2016 09:53:28 +0000 (11:53 +0200)
1  2 
src/collectd.conf.pod
src/processes.c
src/statsd.c

diff --combined src/collectd.conf.pod
@@@ -38,7 -38,7 +38,7 @@@ i.e. a C<E<lt>PluginE<nbsp>...E<gt>> bl
  The syntax of this config file is similar to the config file of the famous
  I<Apache> webserver. Each line contains either an option (a key and a list of
  one or more values) or a section-start or -end. Empty lines and everything
 -after a non-quoted hash-symbol (C<#>) is ignored. I<Keys> are unquoted
 +after a non-quoted hash-symbol (C<#>) are ignored. I<Keys> are unquoted
  strings, consisting only of alphanumeric characters and the underscore (C<_>)
  character. Keys are handled case insensitive by I<collectd> itself and all
  plugins included with it. I<Values> can either be an I<unquoted string>, a
@@@ -70,7 -70,7 +70,7 @@@ C<E<lt>B<Plugin> ...E<gt>> block
  
  =item B<BaseDir> I<Directory>
  
 -Sets the base directory. This is the directory beneath all RRD-files are
 +Sets the base directory. This is the directory beneath which all RRD-files are
  created. Possibly more subdirectories are created. This is also the working
  directory for the daemon.
  
@@@ -83,7 -83,7 +83,7 @@@ I<collectd> will be mostly useless
  Only the first B<LoadPlugin> statement or block for a given plugin name has any
  effect. This is useful when you want to split up the configuration into smaller
  files and want each file to be "self contained", i.e. it contains a B<Plugin>
 -block I<and> then appropriate B<LoadPlugin> statement. The downside is that if
 +block I<and> the appropriate B<LoadPlugin> statement. The downside is that if
  you have multiple conflicting B<LoadPlugin> blocks, e.g. when they specify
  different intervals, only one of them (the first one encountered) will take
  effect and all others will be silently ignored.
@@@ -127,17 -127,8 +127,17 @@@ the average user from ever having to de
  =item B<Interval> I<Seconds>
  
  Sets a plugin-specific interval for collecting metrics. This overrides the
 -global B<Interval> setting. If a plugin provides own support for specifying an
 -interval, that setting will take precedence.
 +global B<Interval> setting. If a plugin provides its own support for specifying
 +an interval, that setting will take precedence.
 +
 +=item B<FlushInterval> I<Seconds>
 +
 +Specifies the interval, in seconds, to call the flush callback if it's
 +defined in this plugin. By default, this is disabled.
 +
 +=item B<FlushTimeout> I<Seconds>
 +
 +Specifies the value of the timeout argument of the flush callback.
  
  =back
  
@@@ -212,7 -203,7 +212,7 @@@ matching C<*.conf> in any subdirectory 
  
  =back
  
 -If more than one files are included by a single B<Include> option, the files
 +If more than one file is included by a single B<Include> option, the files
  will be included in lexicographical order (as defined by the C<strcmp>
  function). Thus, you can e.E<nbsp>g. use numbered prefixes to specify the
  order in which the files are loaded.
@@@ -253,7 -244,7 +253,7 @@@ magic! (Assuming you're using the I<RRD
  
  =item B<MaxReadInterval> I<Seconds>
  
 -Read plugin doubles interval between queries after each failed attempt
 +A read plugin doubles the interval between queries after each failed attempt
  to get data.
  
  This options limits the maximum value of the interval. The default value is
@@@ -526,9 -517,7 +526,9 @@@ are disabled by default
  The I<AMQP plugin> can be used to communicate with other instances of
  I<collectd> or third party applications using an AMQP message broker. Values
  are sent to or received from the broker, which handles routing, queueing and
 -possibly filtering or messages.
 +possibly filtering out messages.
 +
 +B<Synopsis:>
  
   <Plugin "amqp">
     # Send values to an AMQP broker
@@@ -826,24 -815,12 +826,24 @@@ B<apcupsd> can handle it
  
  TCP-Port to connect to. Defaults to B<3551>.
  
 -=item B<ReportSeconds> B<true|false>
 +=item B<ReportSeconds> B<true>|B<false>
  
  If set to B<true>, the time reported in the C<timeleft> metric will be
  converted to seconds. This is the recommended setting. If set to B<false>, the
  default for backwards compatibility, the time will be reported in minutes.
  
 +=item B<PersistentConnection> B<true>|B<false>
 +
 +The plugin is designed to keep the connection to I<apcupsd> open between reads.
 +If plugin poll interval is greater than 15 seconds (hardcoded socket close
 +timeout in I<apcupsd> NIS), then this option is B<false> by default.
 +
 +You can instruct the plugin to close the connection after each read by setting
 +this option to B<false> or force keeping the connection by setting it to B<true>.
 +
 +If I<apcupsd> appears to close the connection due to inactivity quite quickly,
 +the plugin will try to detect this problem and switch to an open-read-close mode.
 +
  =back
  
  =head2 Plugin C<aquaero>
@@@ -1842,7 -1819,6 +1842,7 @@@ than those of other plugins. It usuall
      </Query>
      <Database "product_information">
        Driver "mysql"
 +      Interval 120
        DriverOption "host" "localhost"
        DriverOption "username" "collectd"
        DriverOption "password" "aZo6daiw"
@@@ -2022,11 -1998,6 +2022,11 @@@ the daemon. Other than that, that name 
  
  =over 4
  
 +=item B<Interval> I<Interval>
 +
 +Sets the interval (in seconds) in which the values will be collected from this
 +database. By default the global B<Interval> setting will be used.
 +
  =item B<Driver> I<Driver>
  
  Specifies the driver to use to connect to the database. In many cases those
@@@ -2557,17 -2528,6 +2557,17 @@@ with I<veth> and all interfaces with na
  at least one digit.
  
  
 +=item B<UniqueName> I<true>|I<false>
 +
 +Interface name is not unique on Solaris (KSTAT), interface name is unique
 +only within a module/instance. Following tuple is considered unique:
 +   (ks_module, ks_instance, ks_name)
 +If this option is set to true, interface name contains above three fields
 +separated by an underscore. For more info on KSTAT, visit
 +L<http://docs.oracle.com/cd/E23824_01/html/821-1468/kstat-3kstat.html#REFMAN3Ekstat-3kstat>
 +
 +This option is only available on Solaris.
 +
  =back
  
  =head2 Plugin C<ipmi>
@@@ -3288,146 -3248,6 +3288,146 @@@ B<Collect> option is mandatory
  
  =back
  
 +=head2 Plugin C<mqtt>
 +
 +The I<MQTT plugin> can send metrics to MQTT (B<Publish> blocks) and receive
 +values from MQTT (B<Subscribe> blocks).
 +
 +B<Synopsis:>
 +
 + <Plugin mqtt>
 +   <Publish "name">
 +     Host "mqtt.example.com"
 +     Prefix "collectd"
 +   </Publish>
 +   <Subscribe "name">
 +     Host "mqtt.example.com"
 +     Topic "collectd/#"
 +   </Subscribe>
 + </Plugin>
 +
 +The plugin's configuration is in B<Publish> and/or B<Subscribe> blocks,
 +configuring the sending and receiving direction respectively. The plugin will
 +register a write callback named C<mqtt/I<name>> where I<name> is the string
 +argument given to the B<Publish> block. Both types of blocks share many but not
 +all of the following options. If an option is valid in only one of the blocks,
 +it will be mentioned explicitly.
 +
 +B<Options:>
 +
 +=over 4
 +
 +=item B<Host> I<Hostname>
 +
 +Hostname of the MQTT broker to connect to.
 +
 +=item B<Port> I<Service>
 +
 +Port number or service name of the MQTT broker to connect to.
 +
 +=item B<User> I<UserName>
 +
 +Username used when authenticating to the MQTT broker.
 +
 +=item B<Password> I<Password>
 +
 +Password used when authenticating to the MQTT broker.
 +
 +=item B<ClientId> I<ClientId>
 +
 +MQTT client ID to use. Defaults to the hostname used by I<collectd>.
 +
 +=item B<QoS> [B<0>-B<2>]
 +
 +Sets the I<Quality of Service>, with the values C<0>, C<1> and C<2> meaning:
 +
 +=over 4
 +
 +=item B<0>
 +
 +At most once
 +
 +=item B<1>
 +
 +At least once
 +
 +=item B<2>
 +
 +Exactly once
 +
 +=back
 +
 +In B<Publish> blocks, this option determines the QoS flag set on outgoing
 +messages and defaults to B<0>. In B<Subscribe> blocks, determines the maximum
 +QoS setting the client is going to accept and defaults to B<2>. If the QoS flag
 +on a message is larger than the maximum accepted QoS of a subscriber, the
 +message's QoS will be downgraded.
 +
 +=item B<Prefix> I<Prefix> (Publish only)
 +
 +This plugin will use one topic per I<value list> which will looks like a path.
 +I<Prefix> is used as the first path element and defaults to B<collectd>.
 +
 +An example topic name would be:
 +
 + collectd/cpu-0/cpu-user
 +
 +=item B<Retain> B<false>|B<true> (Publish only)
 +
 +Controls whether the MQTT broker will retain (keep a copy of) the last message
 +sent to each topic and deliver it to new subscribers. Defaults to B<false>.
 +
 +=item B<StoreRates> B<true>|B<false> (Publish only)
 +
 +Controls whether C<DERIVE> and C<COUNTER> metrics are converted to a I<rate>
 +before sending. Defaults to B<true>.
 +
 +=item B<CleanSession> B<true>|B<false> (Subscribe only)
 +
 +Controls whether the MQTT "cleans" the session up after the subscriber
 +disconnects or if it maintains the subscriber's subscriptions and all messages
 +that arrive while the subscriber is disconnected. Defaults to B<true>.
 +
 +=item B<Topic> I<TopicName> (Subscribe only)
 +
 +Configures the topic(s) to subscribe to. You can use the single level C<+> and
 +multi level C<#> wildcards. Defaults to B<collectd/#>, i.e. all topics beneath
 +the B<collectd> branch.
 +
 +=item B<CACert> I<file>
 +
 +Path to the PEM-encoded CA certificate file. Setting this option enables TLS
 +communication with the MQTT broker, and as such, B<Port> should be the TLS-enabled
 +port of the MQTT broker.
 +A valid TLS configuration requires B<CACert>, B<CertificateFile> and B<CertificateKeyFile>.
 +
 +=item B<CertificateFile> I<file>
 +
 +Path to the PEM-encoded certificate file to use as client certificate when
 +connecting to the MQTT broker.
 +A valid TLS configuration requires B<CACert>, B<CertificateFile> and B<CertificateKeyFile>.
 +
 +=item B<CertificateKeyFile> I<file>
 +
 +Path to the unencrypted PEM-encoded key file corresponding to B<CertificateFile>.
 +A valid TLS configuration requires B<CACert>, B<CertificateFile> and B<CertificateKeyFile>.
 +
 +=item B<TLSProtocol> I<protocol>
 +
 +If configured, this specifies the string protocol version (e.g. C<tlsv1>,
 +C<tlsv1.2>) to use for the TLS connection to the broker. If not set a default
 +version is used which depends on the version of OpenSSL the Mosquitto library
 +was linked against.
 +
 +=item B<CipherSuite> I<ciphersuite>
 +
 +A string describing the ciphers available for use. See L<ciphers(1)> and the
 +C<openssl ciphers> utility for more information. If unset, the default ciphers
 +will be used.
 +
 +
 +=back
 +
  =head2 Plugin C<mysql>
  
  The C<mysql plugin> requires B<mysqlclient> to be installed. It connects to
@@@ -4483,21 -4303,6 +4483,21 @@@ Default: C<Collectd notify: %s@%s
  
  =back
  
 +=head2 Plugin C<notify_nagios>
 +
 +The I<notify_nagios> plugin writes notifications to Nagios' I<command file> as
 +a I<passive service check result>.
 +
 +Available configuration options:
 +
 +=over 4
 +
 +=item B<CommandFile> I<Path>
 +
 +Sets the I<command file> to write to. Defaults to F</usr/local/nagios/var/rw/nagios.cmd>.
 +
 +=back
 +
  =head2 Plugin C<ntpd>
  
  The C<ntpd> plugin collects per-peer ntpd data such as time offset and time
@@@ -4735,16 -4540,6 +4735,16 @@@ The following options are accepted with
  Sets the URL to use to connect to the I<OpenLDAP> server. This option is
  I<mandatory>.
  
 +=item B<BindDN> I<BindDN>
 +
 +Name in the form of an LDAP distinguished name intended to be used for
 +authentication. Defaults to empty string to establish an anonymous authorization.
 +
 +=item B<Password> I<Password>
 +
 +Password for simple bind authentication. If this option is not set,
 +unauthenticated bind operation is used.
 +
  =item B<StartTLS> B<true|false>
  
  Defines whether TLS must be used when connecting to the I<OpenLDAP> server.
@@@ -4766,9 -4561,8 +4766,9 @@@ client configuration mechanisms. See ld
  
  =item B<Timeout> I<Seconds>
  
 -Sets the timeout value for ldap operations. Defaults to B<-1> which results in
 -an infinite timeout.
 +Sets the timeout value for ldap operations, in seconds. By default, the
 +configured B<Interval> is used to set the timeout. Use B<-1> to disable
 +(infinite timeout).
  
  =item B<Version> I<Version>
  
@@@ -5017,13 -4811,6 +5017,13 @@@ Default: B<0.9
  
  Sets the Time-To-Live of generated ICMP packets.
  
 +=item B<Size> I<size>
 +
 +Sets the size of the data payload in ICMP packet to specified I<size> (it
 +will be filled with regular ASCII pattern). If not set, default 56 byte
 +long string is used so that the packet size of an ICMPv4 packet is exactly
 +64 bytes, similar to the behaviour of normal ping(1) command.
 +
  =item B<SourceAddress> I<host>
  
  Sets the source address to use. I<host> may either be a numerical network
@@@ -5672,6 -5459,9 +5672,9 @@@ collected for these selected processes 
  (RSS), user- and system-time used, number of processes and number of threads,
  io data (where available) and minor and major pagefaults.
  
+ Some platforms have a limit on the length of process names. I<Name> must stay
+ below this limit.
  =item B<ProcessMatch> I<name> I<regex>
  
  Similar to the B<Process> option this allows to select more detailed
@@@ -5681,10 -5471,6 +5684,10 @@@ dispatched to the daemon using the spec
  allows to "group" several processes together. I<name> must not contain
  slashes.
  
 +=item B<CollectContextSwitch> I<Boolean>
 +
 +Collect context switch of the process.
 +
  =back
  
  =head2 Plugin C<protocols>
@@@ -6151,12 -5937,6 +6154,12 @@@ few ones. This option enables you to d
  I<true> the effect of B<Sensor> is inverted: All selected sensors are ignored
  and all other sensors are collected.
  
 +=item B<UseLabels> I<true>|I<false>
 +
 +Configures how sensor readings are reported. When set to I<true>, sensor
 +readings are reported using their descriptive label (e.g. "VCore"). When set to
 +I<false> (the default) the sensor name is used ("in0").
 +
  =back
  
  =head2 Plugin C<sigrok>
@@@ -6305,12 -6085,6 +6308,12 @@@ rate of counters and size of sets will 
  are unchanged. If set to B<True>, the such metrics are not dispatched and
  removed from the internal cache.
  
 +=item B<CounterSum> B<false>|B<true>
 +
 +When enabled, creates a C<count> metric which reports the change since the last
 +read. This option primarily exists for compatibility with the I<statsd>
 +implementation by Etsy.
 +
  =item B<TimerPercentile> I<Percent>
  
  Calculate and dispatch the configured percentile, i.e. compute the latency, so
@@@ -6919,13 -6693,13 +6922,13 @@@ fails or if you want to disable this fe
  =item B<DigitalTemperatureSensor> I<true>|I<false>
  
  Boolean enabling the collection of the temperature of each core.
 -This option should only be used if the automated detectionfails or 
 +This option should only be used if the automated detectionfails or
  if you want to disable this feature.
  
  =item B<DigitalTemperatureSensor> I<true>|I<false>
  
  Boolean enabling the collection of the temperature of each package.
 -This option should only be used if the automated detectionfails or 
 +This option should only be used if the automated detectionfails or
  if you want to disable this feature.
  
  =item B<TCCActivationTemp> I<Temperature>
@@@ -7265,17 -7039,17 +7268,17 @@@ setting B<name>
  B<address> means use the interface's mac address. This is useful since the
  interface path might change between reboots of a guest or across migrations.
  
 -=item B<PluginInstanceFormat> B<name|uuid>
 +=item B<PluginInstanceFormat> B<name|uuid|none>
  
  When the virt plugin logs data, it sets the plugin_instance of the collected
 -data according to this setting. The default is to use the guest name as provided
 -by the hypervisor, which is equal to setting B<name>.
 +data according to this setting. The default is to not set the plugin_instance.
  
 +B<name> means use the guest's name as provided by the hypervisor.
  B<uuid> means use the guest's UUID.
  
 -You can also specify combinations of these fields. For example B<name uuid>
 -means to concatenate the guest name and UUID (with a literal colon character
 -between, thus I<"foo:1234-1234-1234-1234">).
 +You can also specify combinations of the B<name> and B<uuid> fields.
 +For example B<name uuid> means to concatenate the guest name and UUID
 +(with a literal colon character between, thus I<"foo:1234-1234-1234-1234">).
  
  =back
  
@@@ -7350,14 -7124,6 +7353,14 @@@ Service name or port number to connect 
  
  Protocol to use when connecting to I<Graphite>. Defaults to C<tcp>.
  
 +=item B<ReconnectInterval> I<Seconds>
 +
 +When set to non-zero, forces the connection to the Graphite backend to be
 +closed and re-opend periodically. This behavior is desirable in environments
 +where the connection to the Graphite backend is done through load balancers,
 +for example. When set to zero, the default, the connetion is kept open for as
 +long as possible.
 +
  =item B<LogSendErrors> B<false>|B<true>
  
  If set to B<true> (the default), logs errors when sending data to I<Graphite>.
@@@ -7584,12 -7350,6 +7587,12 @@@ authentication
  
  Password required to load the private key in B<ClientKey>.
  
 +=item B<Header> I<Header>
 +
 +A HTTP header to add to the request.  Multiple headers are added if this option is specified more than once.  Example:
 +
 +  Header "X-Custom-Header: custom_value"
 +
  =item B<SSLVersion> B<SSLv2>|B<SSLv3>|B<TLSv1>|B<TLSv1_0>|B<TLSv1_1>|B<TLSv1_2>
  
  Define which SSL protocol version must be used. By default C<libcurl> will
@@@ -7632,10 -7392,6 +7635,10 @@@ complete. When this limit is reached, t
  all the data in the current send buffer will probably be lost. Defaults to 0,
  which means the connection never times out.
  
 +=item B<LogHttpError> B<false>|B<true>
 +
 +Enables printing of HTTP error code to log. Turned off by default.
 +
  The C<write_http> plugin regularly submits the collected values to the HTTP
  server. How frequently this happens depends on how much data you are collecting
  and the size of B<BufferSize>. The optimal value to set B<Timeout> to is
@@@ -7762,20 -7518,14 +7765,20 @@@ Synopsis
          Host "localhost"
          Port "6379"
          Timeout 1000
 +        Prefix "collectd/"
 +        Database 1
 +        MaxSetSize -1
 +        StoreRates true
      </Node>
    </Plugin>
  
  Values are submitted to I<Sorted Sets>, using the metric name as the key, and
  the timestamp as the score. Retrieving a date range can then be done using the
  C<ZRANGEBYSCORE> I<Redis> command. Additionally, all the identifiers of these
 -I<Sorted Sets> are kept in a I<Set> called C<collectd/values> and can be
 -retrieved using the C<SMEMBERS> I<Redis> command. See
 +I<Sorted Sets> are kept in a I<Set> called C<collectd/values> (or
 +C<${prefix}/values> if the B<Prefix> option was specified) and can be retrieved
 +using the C<SMEMBERS> I<Redis> command. You can specify the database to use
 +with the B<Database> parameter (default is C<0>). See
  L<http://redis.io/commands#sorted_set> and L<http://redis.io/commands#set> for
  details.
  
@@@ -7810,28 -7560,6 +7813,28 @@@ that numerical port numbers must be giv
  
  The B<Timeout> option sets the socket connection timeout, in milliseconds.
  
 +=item B<Prefix> I<Prefix>
 +
 +Prefix used when constructing the name of the I<Sorted Sets> and the I<Set>
 +containing all metrics. Defaults to C<collectd/>, so metrics will have names
 +like C<collectd/cpu-0/cpu-user>. When setting this to something different, it
 +is recommended but not required to include a trailing slash in I<Prefix>.
 +
 +=item B<Database> I<Index>
 +
 +This index selects the redis database to use for writing operations. Defaults
 +to C<0>.
 +
 +=item B<MaxSetSize> I<Items>
 +
 +The B<MaxSetSize> option limits the number of items that the I<Sorted Sets> can
 +hold. Negative values for I<Items> sets no limit, which is the default behavior.
 +
 +=item B<StoreRates> B<true>|B<false>
 +
 +If set to B<true> (the default), convert counter values to rates. If set to
 +B<false> counter values are stored as is, i.e. as an increasing integer number.
 +
  =back
  
  =head2 Plugin C<write_riemann>
@@@ -7876,26 -7604,11 +7879,26 @@@ Hostname or address to connect to. Defa
  
  Service name or port number to connect to. Defaults to C<5555>.
  
 -=item B<Protocol> B<UDP>|B<TCP>
 +=item B<Protocol> B<UDP>|B<TCP>|B<TLS>
  
  Specify the protocol to use when communicating with I<Riemann>. Defaults to
  B<TCP>.
  
 +=item B<TLSCertFile> I<Path>
 +
 +When using the B<TLS> protocol, path to a PEM certificate to present
 +to remote host.
 +
 +=item B<TLSCAFile> I<Path>
 +
 +When using the B<TLS> protocol, path to a PEM CA certificate to
 +use to validate the remote hosts's identity.
 +
 +=item B<TLSKeyFile> I<Path>
 +
 +When using the B<TLS> protocol, path to a PEM private key associated
 +with the certificate defined by B<TLSCertFile>.
 +
  =item B<Batch> B<true>|B<false>
  
  If set to B<true> and B<Protocol> is set to B<TCP>,
@@@ -7915,11 -7628,6 +7918,11 @@@ Defaults to tru
  
  Maximum payload size for a riemann packet. Defaults to 8192
  
 +=item B<BatchFlushTimeout> I<seconds>
 +
 +Maximum amount of seconds to wait in between to batch flushes.
 +No timeout by default.
 +
  =item B<StoreRates> B<true>|B<false>
  
  If set to B<true> (the default), convert counter values to rates. If set to
@@@ -8086,14 -7794,6 +8089,14 @@@ attribute for each metric being sent ou
  
  =back
  
 +=head2 Plugin C<xencpu>
 +
 +This plugin collects metrics of hardware CPU load for machine running Xen
 +hypervisor. Load is calculated from 'idle time' value, provided by Xen.
 +Result is reported using the C<percent> type, for each CPU (core).
 +
 +This plugin doesn't have any options (yet).
 +
  =head2 Plugin C<zookeeper>
  
  The I<zookeeper plugin> will collect statistics from a I<Zookeeper> server
@@@ -8991,8 -8691,6 +8994,8 @@@ Available options
  
  =item B<TypeInstance> I<String>
  
 +=item B<MetaDataSet> I<String> I<String>
 +
  Set the appropriate field to the given string. The strings for plugin instance
  and type instance may be empty, the strings for host and plugin may not be
  empty. It's currently not possible to set the type of a value this way.
diff --combined src/processes.c
  #  undef SAVE_FOB_64
  #endif
  
+ # include <sys/user.h>
  # include <dirent.h>
  /* #endif KERNEL_SOLARIS */
  
@@@ -180,9 -181,6 +181,9 @@@ typedef struct procstat_entry_
        derive_t io_syscr;
        derive_t io_syscw;
  
 +      derive_t cswitch_vol;
 +      derive_t cswitch_invol;
 +
        struct procstat_entry_s *next;
  } procstat_entry_t;
  
@@@ -214,17 -212,12 +215,17 @@@ typedef struct procsta
        derive_t io_syscr;
        derive_t io_syscw;
  
 +      derive_t cswitch_vol;
 +      derive_t cswitch_invol;
 +
        struct procstat   *next;
        struct procstat_entry_s *instances;
  } procstat_t;
  
  static procstat_t *list_head_g = NULL;
  
 +static _Bool report_ctx_switch = 0;
 +
  #if HAVE_THREAD_INFO
  static mach_port_t port_host_self;
  static mach_port_t port_task_self;
@@@ -262,19 -255,20 +263,19 @@@ static void ps_list_register (const cha
        procstat_t *ptr;
        int status;
  
 -      new = (procstat_t *) malloc (sizeof (procstat_t));
 +      new = calloc (1, sizeof (*new));
        if (new == NULL)
        {
 -              ERROR ("processes plugin: ps_list_register: malloc failed.");
 +              ERROR ("processes plugin: ps_list_register: calloc failed.");
                return;
        }
 -      memset (new, 0, sizeof (procstat_t));
        sstrncpy (new->name, name, sizeof (new->name));
  
  #if HAVE_REGEX_H
        if (regexp != NULL)
        {
                DEBUG ("ProcessMatch: adding \"%s\" as criteria to process %s.", regexp, name);
 -              new->re = (regex_t *) malloc (sizeof (regex_t));
 +              new->re = malloc (sizeof (*new->re));
                if (new->re == NULL)
                {
                        ERROR ("processes plugin: ps_list_register: malloc failed.");
                if (status != 0)
                {
                        DEBUG ("ProcessMatch: compiling the regular expression \"%s\" failed.", regexp);
 -                      sfree(new->re);
 -                      sfree(new);
 +                      sfree (new->re);
 +                      sfree (new);
                        return;
                }
        }
@@@ -360,31 -354,6 +361,31 @@@ static int ps_list_match (const char *n
        return (0);
  } /* int ps_list_match */
  
 +static void ps_update_counter (
 +        _Bool init,
 +        derive_t *group_counter,
 +        derive_t *curr_counter, unsigned long *curr_value,
 +        derive_t new_counter, unsigned long new_value) {
 +    if (init)
 +    {
 +        *curr_value = new_value;
 +        *curr_counter += new_value;
 +        *group_counter += new_value;
 +        return;
 +    }
 +
 +    if (new_counter < *curr_counter)
 +    {
 +        *curr_value = new_counter + (ULONG_MAX - *curr_counter);
 +    }
 +    else
 +    {
 +        *curr_value = new_counter - *curr_counter;
 +    }
 +    *curr_counter = new_counter;
 +    *group_counter += *curr_value;
 +}
 +
  /* add process entry to 'instances' of process 'name' (or refresh it) */
  static void ps_list_add (const char *name, const char *cmdline, procstat_entry_t *entry)
  {
  
        for (ps = list_head_g; ps != NULL; ps = ps->next)
        {
 +        _Bool want_init;
 +
                if ((ps_list_match (name, cmdline, ps)) == 0)
                        continue;
  
                {
                        procstat_entry_t *new;
  
 -                      new = (procstat_entry_t *) malloc (sizeof (procstat_entry_t));
 +                      new = calloc (1, sizeof (*new));
                        if (new == NULL)
                                return;
 -                      memset (new, 0, sizeof (procstat_entry_t));
                        new->id = entry->id;
  
                        if (pse == NULL)
                pse->io_wchar   = entry->io_wchar;
                pse->io_syscr   = entry->io_syscr;
                pse->io_syscw   = entry->io_syscw;
 +              pse->cswitch_vol   = entry->cswitch_vol;
 +              pse->cswitch_invol = entry->cswitch_invol;
  
                ps->num_proc   += pse->num_proc;
                ps->num_lwp    += pse->num_lwp;
                ps->io_syscr   += ((pse->io_syscr == -1)?0:pse->io_syscr);
                ps->io_syscw   += ((pse->io_syscw == -1)?0:pse->io_syscw);
  
 -              if ((entry->vmem_minflt_counter == 0)
 -                              && (entry->vmem_majflt_counter == 0))
 -              {
 -                      pse->vmem_minflt_counter += entry->vmem_minflt;
 -                      pse->vmem_minflt = entry->vmem_minflt;
 -
 -                      pse->vmem_majflt_counter += entry->vmem_majflt;
 -                      pse->vmem_majflt = entry->vmem_majflt;
 -              }
 -              else
 -              {
 -                      if (entry->vmem_minflt_counter < pse->vmem_minflt_counter)
 -                      {
 -                              pse->vmem_minflt = entry->vmem_minflt_counter
 -                                      + (ULONG_MAX - pse->vmem_minflt_counter);
 -                      }
 -                      else
 -                      {
 -                              pse->vmem_minflt = entry->vmem_minflt_counter - pse->vmem_minflt_counter;
 -                      }
 -                      pse->vmem_minflt_counter = entry->vmem_minflt_counter;
 -
 -                      if (entry->vmem_majflt_counter < pse->vmem_majflt_counter)
 -                      {
 -                              pse->vmem_majflt = entry->vmem_majflt_counter
 -                                      + (ULONG_MAX - pse->vmem_majflt_counter);
 -                      }
 -                      else
 -                      {
 -                              pse->vmem_majflt = entry->vmem_majflt_counter - pse->vmem_majflt_counter;
 -                      }
 -                      pse->vmem_majflt_counter = entry->vmem_majflt_counter;
 -              }
 -
 -              ps->vmem_minflt_counter += pse->vmem_minflt;
 -              ps->vmem_majflt_counter += pse->vmem_majflt;
 -
 -              if ((entry->cpu_user_counter == 0)
 -                              && (entry->cpu_system_counter == 0))
 -              {
 -                      pse->cpu_user_counter += entry->cpu_user;
 -                      pse->cpu_user = entry->cpu_user;
 -
 -                      pse->cpu_system_counter += entry->cpu_system;
 -                      pse->cpu_system = entry->cpu_system;
 -              }
 -              else
 -              {
 -                      if (entry->cpu_user_counter < pse->cpu_user_counter)
 -                      {
 -                              pse->cpu_user = entry->cpu_user_counter
 -                                      + (ULONG_MAX - pse->cpu_user_counter);
 -                      }
 -                      else
 -                      {
 -                              pse->cpu_user = entry->cpu_user_counter - pse->cpu_user_counter;
 -                      }
 -                      pse->cpu_user_counter = entry->cpu_user_counter;
 -
 -                      if (entry->cpu_system_counter < pse->cpu_system_counter)
 -                      {
 -                              pse->cpu_system = entry->cpu_system_counter
 -                                      + (ULONG_MAX - pse->cpu_system_counter);
 -                      }
 -                      else
 -                      {
 -                              pse->cpu_system = entry->cpu_system_counter - pse->cpu_system_counter;
 -                      }
 -                      pse->cpu_system_counter = entry->cpu_system_counter;
 -              }
 -
 -              ps->cpu_user_counter   += pse->cpu_user;
 -              ps->cpu_system_counter += pse->cpu_system;
 +              ps->cswitch_vol   += ((pse->cswitch_vol == -1)?0:pse->cswitch_vol);
 +              ps->cswitch_invol += ((pse->cswitch_invol == -1)?0:pse->cswitch_invol);
 +
 +              want_init = (entry->vmem_minflt_counter == 0)
 +                              && (entry->vmem_majflt_counter == 0);
 +              ps_update_counter (want_init,
 +                              &ps->vmem_minflt_counter,
 +                              &pse->vmem_minflt_counter, &pse->vmem_minflt,
 +                              entry->vmem_minflt_counter, entry->vmem_minflt);
 +              ps_update_counter (want_init,
 +                              &ps->vmem_majflt_counter,
 +                              &pse->vmem_majflt_counter, &pse->vmem_majflt,
 +                              entry->vmem_majflt_counter, entry->vmem_majflt);
 +
 +              want_init = (entry->cpu_user_counter == 0)
 +                              && (entry->cpu_system_counter == 0);
 +              ps_update_counter (want_init,
 +                              &ps->cpu_user_counter,
 +                              &pse->cpu_user_counter, &pse->cpu_user,
 +                              entry->cpu_user_counter, entry->cpu_user);
 +              ps_update_counter (want_init,
 +                              &ps->cpu_system_counter,
 +                              &pse->cpu_system_counter, &pse->cpu_system,
 +                              entry->cpu_system_counter, entry->cpu_system);
        }
  }
  
@@@ -497,8 -512,6 +498,8 @@@ static void ps_list_reset (void
                ps->io_wchar = -1;
                ps->io_syscr = -1;
                ps->io_syscw = -1;
 +              ps->cswitch_vol   = -1;
 +              ps->cswitch_invol = -1;
  
                pse_prev = NULL;
                pse = ps->instances;
@@@ -538,6 -551,12 +539,12 @@@ static int ps_config (oconfig_item_t *c
  {
        int i;
  
+ #if KERNEL_LINUX
+       const size_t max_procname_len = 15;
+ #elif KERNEL_SOLARIS || KERNEL_FREEBSD
+       const size_t max_procname_len = MAXCOMLEN -1;
+ #endif
        for (i = 0; i < ci->children_num; ++i) {
                oconfig_item_t *c = ci->children + i;
  
                                                c->children_num, c->values[0].value.string);
                        }
  
+ #if KERNEL_LINUX || KERNEL_SOLARIS || KERNEL_FREEBSD
+                       if (strlen (c->values[0].value.string) > max_procname_len) {
+                               WARNING ("processes plugin: this platform has a %zu character limit "
+                                               "to process names. The `Process \"%s\"' option will "
+                                               "not work as expected.",
+                                               max_procname_len, c->values[0].value.string);
+                       }
+ #endif
                        ps_list_register (c->values[0].value.string, NULL);
                }
                else if (strcasecmp (c->key, "ProcessMatch") == 0)
                        ps_list_register (c->values[0].value.string,
                                        c->values[1].value.string);
                }
 +              else if (strcasecmp (c->key, "CollectContextSwitch") == 0)
 +              {
 +                      cf_util_get_boolean (c, &report_ctx_switch);
 +              }
                else
                {
                        ERROR ("processes plugin: The `%s' configuration option is not "
@@@ -736,36 -760,19 +752,36 @@@ static void ps_submit_proc_list (procst
                plugin_dispatch_values (&vl);
        }
  
 +      if ( report_ctx_switch )
 +      {
 +              sstrncpy (vl.type, "contextswitch", sizeof (vl.type));
 +              sstrncpy (vl.type_instance, "voluntary", sizeof (vl.type_instance));
 +              vl.values[0].derive = ps->cswitch_vol;
 +              vl.values_len = 1;
 +              plugin_dispatch_values (&vl);
 +
 +              sstrncpy (vl.type, "contextswitch", sizeof (vl.type));
 +              sstrncpy (vl.type_instance, "involuntary", sizeof (vl.type_instance));
 +              vl.values[0].derive = ps->cswitch_invol;
 +              vl.values_len = 1;
 +              plugin_dispatch_values (&vl);
 +      }
 +
        DEBUG ("name = %s; num_proc = %lu; num_lwp = %lu; "
                        "vmem_size = %lu; vmem_rss = %lu; vmem_data = %lu; "
                        "vmem_code = %lu; "
                        "vmem_minflt_counter = %"PRIi64"; vmem_majflt_counter = %"PRIi64"; "
                        "cpu_user_counter = %"PRIi64"; cpu_system_counter = %"PRIi64"; "
                        "io_rchar = %"PRIi64"; io_wchar = %"PRIi64"; "
 -                      "io_syscr = %"PRIi64"; io_syscw = %"PRIi64";",
 +                      "io_syscr = %"PRIi64"; io_syscw = %"PRIi64"; "
 +                      "cswitch_vol = %"PRIi64"; cswitch_invol = %"PRIi64";",
                        ps->name, ps->num_proc, ps->num_lwp,
                        ps->vmem_size, ps->vmem_rss,
                        ps->vmem_data, ps->vmem_code,
                        ps->vmem_minflt_counter, ps->vmem_majflt_counter,
                        ps->cpu_user_counter, ps->cpu_system_counter,
 -                      ps->io_rchar, ps->io_wchar, ps->io_syscr, ps->io_syscw);
 +                      ps->io_rchar, ps->io_wchar, ps->io_syscr, ps->io_syscw,
 +                      ps->cswitch_vol, ps->cswitch_invol);
  } /* void ps_submit_proc_list */
  
  #if KERNEL_LINUX || KERNEL_SOLARIS
@@@ -790,99 -797,42 +806,99 @@@ static void ps_submit_fork_rate (derive
  
  /* ------- additional functions for KERNEL_LINUX/HAVE_THREAD_INFO ------- */
  #if KERNEL_LINUX
 -static int ps_read_tasks (long pid)
 +static procstat_t *ps_read_tasks_status (long pid, procstat_t *ps)
  {
        char           dirname[64];
        DIR           *dh;
 +      char           filename[64];
 +      FILE          *fh;
        struct dirent *ent;
 -      int count = 0;
 +      derive_t cswitch_vol = 0;
 +      derive_t cswitch_invol = 0;
 +      char buffer[1024];
 +      char *fields[8];
 +      int numfields;
  
        ssnprintf (dirname, sizeof (dirname), "/proc/%li/task", pid);
  
        if ((dh = opendir (dirname)) == NULL)
        {
                DEBUG ("Failed to open directory `%s'", dirname);
 -              return (-1);
 +              return (NULL);
        }
  
        while ((ent = readdir (dh)) != NULL)
        {
 +              char *tpid;
 +
                if (!isdigit ((int) ent->d_name[0]))
                        continue;
 -              else
 -                      count++;
 +
 +              tpid = ent->d_name;
 +
 +              ssnprintf (filename, sizeof (filename), "/proc/%li/task/%s/status", pid, tpid);
 +              if ((fh = fopen (filename, "r")) == NULL)
 +              {
 +                      DEBUG ("Failed to open file `%s'", filename);
 +                      continue;
 +              }
 +
 +              while (fgets (buffer, sizeof(buffer), fh) != NULL)
 +              {
 +                      derive_t tmp;
 +                      char *endptr;
 +
 +                      if (strncmp (buffer, "voluntary_ctxt_switches", 23) != 0
 +                              && strncmp (buffer, "nonvoluntary_ctxt_switches", 26) != 0)
 +                              continue;
 +
 +                      numfields = strsplit (buffer, fields,
 +                              STATIC_ARRAY_SIZE (fields));
 +
 +                      if (numfields < 2)
 +                              continue;
 +
 +                      errno = 0;
 +                      endptr = NULL;
 +                      tmp = (derive_t) strtoll (fields[1], &endptr, /* base = */ 10);
 +                      if ((errno == 0) && (endptr != fields[1]))
 +                      {
 +                              if (strncmp (buffer, "voluntary_ctxt_switches", 23) == 0)
 +                              {
 +                                      cswitch_vol += tmp;
 +                              }
 +                              else if (strncmp (buffer, "nonvoluntary_ctxt_switches", 26) == 0)
 +                              {
 +                                      cswitch_invol += tmp;
 +                              }
 +                      }
 +              } /* while (fgets) */
 +
 +              if (fclose (fh))
 +              {
 +                      char errbuf[1024];
 +                              WARNING ("processes: fclose: %s",
 +                                      sstrerror (errno, errbuf, sizeof (errbuf)));
 +              }
        }
        closedir (dh);
  
 -      return ((count >= 1) ? count : 1);
 -} /* int *ps_read_tasks */
 +      ps->cswitch_vol = cswitch_vol;
 +      ps->cswitch_invol = cswitch_invol;
  
 -/* Read advanced virtual memory data from /proc/pid/status */
 -static procstat_t *ps_read_vmem (long pid, procstat_t *ps)
 +      return (ps);
 +} /* int *ps_read_tasks_status */
 +
 +/* Read data from /proc/pid/status */
 +static procstat_t *ps_read_status (long pid, procstat_t *ps)
  {
        FILE *fh;
        char buffer[1024];
        char filename[64];
 -      unsigned long long lib = 0;
 -      unsigned long long exe = 0;
 -      unsigned long long data = 0;
 +      unsigned long lib = 0;
 +      unsigned long exe = 0;
 +      unsigned long data = 0;
 +      unsigned long threads = 0;
        char *fields[8];
        int numfields;
  
  
        while (fgets (buffer, sizeof(buffer), fh) != NULL)
        {
 -              long long tmp;
 +              unsigned long tmp;
                char *endptr;
  
 -              if (strncmp (buffer, "Vm", 2) != 0)
 +              if (strncmp (buffer, "Vm", 2) != 0
 +                              && strncmp (buffer, "Threads", 7) != 0)
                        continue;
  
                numfields = strsplit (buffer, fields,
  
                errno = 0;
                endptr = NULL;
 -              tmp = strtoll (fields[1], &endptr, /* base = */ 10);
 +              tmp = strtoul (fields[1], &endptr, /* base = */ 10);
                if ((errno == 0) && (endptr != fields[1]))
                {
                        if (strncmp (buffer, "VmData", 6) == 0)
                        {
                                exe = tmp;
                        }
 +                      else if  (strncmp(buffer, "Threads", 7) == 0)
 +                      {
 +                              threads = tmp;
 +                      }
                }
        } /* while (fgets) */
  
  
        ps->vmem_data = data * 1024;
        ps->vmem_code = (exe + lib) * 1024;
 +      if (threads != 0)
 +              ps->num_lwp = threads;
  
        return (ps);
  } /* procstat_t *ps_read_vmem */
@@@ -1007,9 -950,9 +1023,9 @@@ static int ps_read_process (long pid, p
        char *fields[64];
        char  fields_len;
  
 -      int   buffer_len;
 +      size_t buffer_len;
  
 -      char *buffer_ptr;
 +      char  *buffer_ptr;
        size_t name_start_pos;
        size_t name_end_pos;
        size_t name_len;
        long long unsigned vmem_rss;
        long long unsigned stack_size;
  
 +      ssize_t status;
 +
        memset (ps, 0, sizeof (procstat_t));
  
        ssnprintf (filename, sizeof (filename), "/proc/%li/stat", pid);
  
 -      buffer_len = read_file_contents (filename,
 -                      buffer, sizeof(buffer) - 1);
 -      if (buffer_len <= 0)
 +      status = read_file_contents (filename, buffer, sizeof(buffer) - 1);
 +      if (status <= 0)
                return (-1);
 +      buffer_len = (size_t) status;
        buffer[buffer_len] = 0;
  
        /* The name of the process is enclosed in parens. Since the name can
         * strchr(3) and strrchr(3) to avoid pointer arithmetic which would
         * otherwise be required to determine name_len. */
        name_start_pos = 0;
 -      while ((buffer[name_start_pos] != '(')
 -                      && (name_start_pos < buffer_len))
 +      while (name_start_pos < buffer_len && buffer[name_start_pos] != '(')
                name_start_pos++;
  
        name_end_pos = buffer_len;
 -      while ((buffer[name_end_pos] != ')')
 -                      && (name_end_pos > 0))
 +      while (name_end_pos > 0 && buffer[name_end_pos] != ')')
                name_end_pos--;
  
        /* Either '(' or ')' is not found or they are in the wrong order.
        }
        else
        {
 -              if ( (ps->num_lwp = ps_read_tasks (pid)) == -1 )
 +              ps->num_lwp = strtoul (fields[17], /* endptr = */ NULL, /* base = */ 10);
 +              if ((ps_read_status(pid, ps)) == NULL)
                {
 -                      /* returns -1 => kernel 2.4 */
 -                      ps->num_lwp = 1;
 +                      /* No VMem data */
 +                      ps->vmem_data = -1;
 +                      ps->vmem_code = -1;
 +                      DEBUG("ps_read_process: did not get vmem data for pid %li", pid);
                }
 +              if (ps->num_lwp == 0)
 +                      ps->num_lwp = 1;
                ps->num_proc = 1;
        }
  
        cpu_system_counter = cpu_system_counter * 1000000 / CONFIG_HZ;
        vmem_rss = vmem_rss * pagesize_g;
  
 -      if ( (ps_read_vmem(pid, ps)) == NULL)
 -      {
 -              /* No VMem data */
 -              ps->vmem_data = -1;
 -              ps->vmem_code = -1;
 -              DEBUG("ps_read_process: did not get vmem data for pid %li", pid);
 -      }
 -
        ps->cpu_user_counter = cpu_user_counter;
        ps->cpu_system_counter = cpu_system_counter;
        ps->vmem_size = (unsigned long) vmem_size;
                DEBUG("ps_read_process: not get io data for pid %li", pid);
        }
  
 +      if ( report_ctx_switch )
 +      {
 +              if ( (ps_read_tasks_status(pid, ps)) == NULL)
 +              {
 +                      ps->cswitch_vol = -1;
 +                      ps->cswitch_invol = -1;
 +
 +                      DEBUG("ps_read_tasks_status: not get context "
 +                                      "switch data for pid %li", pid);
 +              }
 +      }
 +
        /* success */
        return (0);
  } /* int ps_read_process (...) */
@@@ -1214,7 -1148,7 +1230,7 @@@ static char *ps_get_cmdline (long pid, 
                buf_ptr += status;
                len     -= status;
  
 -              if (len <= 0)
 +              if (len == 0)
                        break;
        }
  
@@@ -1303,16 -1237,16 +1319,16 @@@ static char *ps_get_cmdline (long pid, 
  {
        char path[PATH_MAX];
        psinfo_t info;
 -      int status;
 +      ssize_t status;
  
        snprintf(path, sizeof (path), "/proc/%li/psinfo", pid);
  
        status = read_file_contents (path, (void *) &info, sizeof (info));
 -      if (status != sizeof (info))
 +      if ((status < 0) || (((size_t) status) != sizeof (info)))
        {
                ERROR ("processes plugin: Unexpected return value "
                                "while reading \"%s\": "
 -                              "Returned %i but expected %zu.",
 +                              "Returned %zd but expected %zu.",
                                path, status, buffer_size);
                return (NULL);
        }
@@@ -1344,15 -1278,18 +1360,15 @@@ static int ps_read_process(long pid, pr
        snprintf(f_usage, sizeof (f_usage), "/proc/%li/usage", pid);
  
  
 -      buffer = malloc(sizeof (pstatus_t));
 -      memset(buffer, 0, sizeof (pstatus_t));
 +      buffer = calloc(1, sizeof (pstatus_t));
        read_file_contents(filename, buffer, sizeof (pstatus_t));
        myStatus = (pstatus_t *) buffer;
  
 -      buffer = malloc(sizeof (psinfo_t));
 -      memset(buffer, 0, sizeof(psinfo_t));
 +      buffer = calloc(1, sizeof (psinfo_t));
        read_file_contents(f_psinfo, buffer, sizeof (psinfo_t));
        myInfo = (psinfo_t *) buffer;
  
 -      buffer = malloc(sizeof (prusage_t));
 -      memset(buffer, 0, sizeof(prusage_t));
 +      buffer = calloc(1, sizeof (prusage_t));
        read_file_contents(f_usage, buffer, sizeof (prusage_t));
        myUsage = (prusage_t *) buffer;
  
        ps->io_syscr = myUsage->pr_sysc;
        ps->io_syscw = myUsage->pr_sysc;
  
 +      /*
 +       * TODO: context switch counters for Solaris
 +   */
 +      ps->cswitch_vol   = -1;
 +      ps->cswitch_invol = -1;
 +
  
        /*
         * TODO: Find way of setting BLOCKED and PAGING status
   * are retrieved from kstat (module cpu, name sys, class misc, stat nthreads).
   * The result is the sum for all the threads created on each cpu
   */
 -static int read_fork_rate()
 +static int read_fork_rate (void)
  {
        extern kstat_ctl_t *kc;
        kstat_t *ksp_chain = NULL;
@@@ -1653,10 -1584,6 +1669,10 @@@ static int ps_read (void
  
                                pse.cpu_user_counter = task_absolutetime_info.total_user;
                                pse.cpu_system_counter = task_absolutetime_info.total_system;
 +
 +                              /* context switch counters not implemented */
 +                              pse.cswitch_vol   = -1;
 +                              pse.cswitch_invol = -1;
                        }
  
                        status = task_threads (task_list[task], &thread_list,
                pse.io_syscr = ps.io_syscr;
                pse.io_syscw = ps.io_syscw;
  
 +              pse.cswitch_vol = ps.cswitch_vol;
 +              pse.cswitch_invol = ps.cswitch_invol;
 +
                switch (state)
                {
                        case 'R': running++;  break;
                        pse.io_syscr = -1;
                        pse.io_syscw = -1;
  
 +                      /* context switch counters not implemented */
 +                      pse.cswitch_vol   = -1;
 +                      pse.cswitch_invol = -1;
 +
                        ps_list_add (procs[i].ki_comm, have_cmdline ? cmdline : NULL, &pse);
  
                        switch (procs[i].ki_stat)
                        pse.io_syscr = -1;
                        pse.io_syscw = -1;
  
 +                      /* context switch counters not implemented */
 +                      pse.cswitch_vol   = -1;
 +                      pse.cswitch_invol = -1;
 +
                        ps_list_add (procs[i].p_comm, have_cmdline ? cmdline : NULL, &pse);
  
                        switch (procs[i].p_stat)
                        pse.io_syscr = -1;
                        pse.io_syscw = -1;
  
 +                      pse.cswitch_vol   = -1;
 +                      pse.cswitch_invol = -1;
 +
                        ps_list_add (cmdline, cargs, &pse);
                } /* for (i = 0 .. nprocs) */
  
                pse.io_syscr = ps.io_syscr;
                pse.io_syscw = ps.io_syscw;
  
 +              pse.cswitch_vol = -1;
 +              pse.cswitch_invol = -1;
 +
                switch (state)
                {
                        case 'R': running++;  break;
diff --combined src/statsd.c
@@@ -35,6 -35,7 +35,6 @@@
  #include <pthread.h>
  
  #include <sys/types.h>
 -#include <sys/socket.h>
  #include <netdb.h>
  #include <poll.h>
  
@@@ -64,7 -65,6 +64,7 @@@ struct statsd_metric_
  {
    metric_type_t type;
    double value;
 +  derive_t counter;
    latency_counter_t *latency;
    c_avl_tree_t *set;
    unsigned long updates_num;
@@@ -89,7 -89,6 +89,7 @@@ static _Bool conf_delete_sets     = 0
  static double *conf_timer_percentile = NULL;
  static size_t  conf_timer_percentile_num = 0;
  
 +static _Bool conf_counter_sum     = 0;
  static _Bool conf_timer_lower     = 0;
  static _Bool conf_timer_upper     = 0;
  static _Bool conf_timer_sum       = 0;
@@@ -127,13 -126,14 +127,13 @@@ static statsd_metric_t *statsd_metric_l
      return (NULL);
    }
  
 -  metric = malloc (sizeof (*metric));
 +  metric = calloc (1, sizeof (*metric));
    if (metric == NULL)
    {
 -    ERROR ("statsd plugin: malloc failed.");
 +    ERROR ("statsd plugin: calloc failed.");
      sfree (key_copy);
      return (NULL);
    }
 -  memset (metric, 0, sizeof (*metric));
  
    metric->type = type;
    metric->latency = NULL;
@@@ -262,8 -262,6 +262,8 @@@ static int statsd_handle_counter (char 
    if (status != 0)
      return (status);
  
 +  /* Changes to the counter are added to (statsd_metric_t*)->value. ->counter is
 +   * only updated in statsd_metric_submit_unsafe(). */
    return (statsd_metric_add (name, (double) (value.gauge / scale.gauge),
          STATSD_COUNTER));
  } /* }}} int statsd_handle_counter */
@@@ -688,8 -686,6 +688,8 @@@ static int statsd_config (oconfig_item_
        cf_util_get_boolean (child, &conf_delete_gauges);
      else if (strcasecmp ("DeleteSets", child->key) == 0)
        cf_util_get_boolean (child, &conf_delete_sets);
 +    else if (strcasecmp ("CounterSum", child->key) == 0)
 +      cf_util_get_boolean (child, &conf_counter_sum);
      else if (strcasecmp ("TimerLower", child->key) == 0)
        cf_util_get_boolean (child, &conf_timer_lower);
      else if (strcasecmp ("TimerUpper", child->key) == 0)
@@@ -760,7 -756,8 +760,7 @@@ static int statsd_metric_clear_set_unsa
  } /* }}} int statsd_metric_clear_set_unsafe */
  
  /* Must hold metrics_lock when calling this function. */
 -static int statsd_metric_submit_unsafe (char const *name, /* {{{ */
 -    statsd_metric_t const *metric)
 +static int statsd_metric_submit_unsafe (char const *name, statsd_metric_t *metric) /* {{{ */
  {
    value_t values[1];
    value_list_t vl = VALUE_LIST_INIT;
        values[0].gauge = (gauge_t) c_avl_size (metric->set);
    }
    else { /* STATSD_COUNTER */
 -      /*
 -       * Expand a single value to two metrics:
 -       *
 -       * - The absolute counter, as a gauge
 -       * - A derived rate for this counter
 -       */
 -      values[0].derive = (derive_t) metric->value;
 -      plugin_dispatch_values(&vl);
 -
 -      sstrncpy(vl.type, "gauge", sizeof (vl.type));
 -      values[0].gauge = (gauge_t) metric->value;
 +    gauge_t delta = nearbyint (metric->value);
 +
 +    /* Etsy's statsd writes counters as two metrics: a rate and the change since
 +     * the last write. Since collectd does not reset its DERIVE metrics to zero,
 +     * this makes little sense, but we're dispatching a "count" metric here
 +     * anyway - if requested by the user - for compatibility reasons. */
 +    if (conf_counter_sum)
 +    {
 +      sstrncpy (vl.type, "count", sizeof (vl.type));
 +      values[0].gauge = delta;
 +      plugin_dispatch_values (&vl);
 +
 +      /* restore vl.type */
 +      sstrncpy (vl.type, "derive", sizeof (vl.type));
 +    }
 +
 +    /* Rather than resetting value to zero, subtract delta so we correctly keep
 +     * track of residuals. */
 +    metric->value   -= delta;
 +    metric->counter += (derive_t) delta;
 +
 +    values[0].derive = metric->counter;
    }
  
    return (plugin_dispatch_values (&vl));
@@@ -955,8 -941,6 +955,6 @@@ static int statsd_shutdown (void) /* {{
    void *key;
    void *value;
  
-   pthread_mutex_lock (&metrics_lock);
    if (network_thread_running)
    {
      network_thread_shutdown = 1;
    }
    network_thread_running = 0;
  
+   pthread_mutex_lock (&metrics_lock);
    while (c_avl_pick (metrics_tree, &key, &value) == 0)
    {
      sfree (key);