Whamcloud - gitweb
b=16098
[fs/lustre-release.git] / lustre / obdclass / lu_time.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/obdclass/lu_time.c
37  *
38  * Lustre Time Tracking.
39  * These are the only exported functions, they provide some generic
40  * infrastructure for managing object devices.
41  *
42  * Author: Nikita Danilov <nikita@clusterfs.com>
43  */
44
45 #define DEBUG_SUBSYSTEM S_CLASS
46 #ifndef EXPORT_SYMTAB
47 # define EXPORT_SYMTAB
48 #endif
49
50 /* OBD_{ALLOC,FREE}_PTR() */
51 #include <obd_support.h>
52 #include <lprocfs_status.h>
53 #include <lu_object.h>
54 #include <lu_time.h>
55
56 enum {
57         LU_TIME_DEPTH_MAX = 16
58 };
59
60 struct lu_time_data {
61         int                ltd_tos; /* top of the stack */
62         unsigned long long ltd_timestamp[LU_TIME_DEPTH_MAX];
63 };
64
65 /* context key constructor/destructor: lu_time_key_init, lu_time_key_fini */
66 LU_KEY_INIT_FINI(lu_time, struct lu_time_data);
67
68 void lu_time_key_exit(const struct lu_context *ctx,
69                       struct lu_context_key *key, void *data)
70 {
71         struct lu_time_data *value = data;
72         LASSERT(value->ltd_tos == 0);
73 }
74
75 /*
76  * Key, holding temporary buffer. This key is registered very early by
77  * lu_global_init().
78  */
79 static struct lu_context_key lu_time_key = {
80         .lct_tags = LCT_MD_THREAD|LCT_DT_THREAD|LCT_CL_THREAD,
81         .lct_init = lu_time_key_init,
82         .lct_fini = lu_time_key_fini,
83         .lct_exit = lu_time_key_exit
84 };
85
86 int lu_time_global_init(void)
87 {
88         LU_CONTEXT_KEY_INIT(&lu_time_key);
89         return lu_context_key_register(&lu_time_key);
90 }
91
92 void lu_time_global_fini(void)
93 {
94         lu_context_key_degister(&lu_time_key);
95 }
96
97 int lu_time_named_init(struct lprocfs_stats **stats, const char *name,
98                        cfs_proc_dir_entry_t *entry,
99                        const char **names, int nr)
100 {
101         int result;
102         int i;
103
104         ENTRY;
105
106         *stats = NULL;
107         if (nr == 0)
108                 RETURN(0);
109
110         *stats = lprocfs_alloc_stats(nr, 0);
111         if (*stats != NULL) {
112                 result = lprocfs_register_stats(entry, name, *stats);
113                 if (result == 0) {
114                         for (i = 0; i < nr; ++i) {
115                                 lprocfs_counter_init(*stats, i,
116                                                      LPROCFS_CNTR_AVGMINMAX,
117                                                      names[i], "usec");
118                         }
119                 }
120         } else
121                 result = -ENOMEM;
122
123         if (result != 0)
124                 lu_time_fini(stats);
125
126         RETURN(result);
127 }
128 EXPORT_SYMBOL(lu_time_named_init);
129
130 int lu_time_init(struct lprocfs_stats **stats, cfs_proc_dir_entry_t *entry,
131                  const char **names, int nr)
132 {
133         return lu_time_named_init(stats, "stats", entry, names, nr);
134 }
135 EXPORT_SYMBOL(lu_time_init);
136
137 void lu_time_fini(struct lprocfs_stats **stats)
138 {
139         if (*stats != NULL) {
140                 lprocfs_free_stats(stats);
141                 *stats = NULL;
142         }
143 }
144 EXPORT_SYMBOL(lu_time_fini);
145
146 static inline struct lu_time_data *lu_time_data_get(const struct lu_env *env)
147 {
148         return lu_context_key_get(&env->le_ctx, &lu_time_key);
149 }
150
151 int lu_time_is_clean(const struct lu_env *env)
152 {
153         return lu_time_data_get(env)->ltd_tos == 0;
154 }
155 EXPORT_SYMBOL(lu_time_is_clean);
156
157 /* from sleepometer by Andrew Morton */
158 unsigned long long lu_time_stamp_get(void)
159 {
160         /*
161          * Return timestamp with microsecond precision. This has to be cheap.
162          */
163 //#ifdef CONFIG_X86 
164 #if defined(CONFIG_X86) && !defined(CONFIG_X86_64)
165         /*
166          * do_gettimeofday() goes backwards sometimes :(.  Usethe TSC
167          */
168         unsigned long long ret;
169
170         rdtscll(ret);
171         do_div(ret, cpu_khz / 1000);
172         return ret;
173 #else
174         struct timeval now;
175         unsigned long long ret;
176
177         do_gettimeofday(&now);
178         ret = now.tv_sec;
179         ret *= 1000000;
180         ret += now.tv_usec;
181         return ret;
182 #endif
183 }
184 /*
185  * Export it, but do not advertise in headers. This is limited use only.
186  */
187 EXPORT_SYMBOL(lu_time_stamp_get);
188
189 void lu_lprocfs_time_start(const struct lu_env *env)
190 {
191         struct lu_time_data *ltd = lu_time_data_get(env);
192
193         LASSERT(0 <= ltd->ltd_tos);
194         LASSERT(ltd->ltd_tos < ARRAY_SIZE(ltd->ltd_timestamp));
195         ltd->ltd_timestamp[ltd->ltd_tos++] = lu_time_stamp_get();
196 }
197 EXPORT_SYMBOL(lu_lprocfs_time_start);
198
199 void lu_lprocfs_time_end(const struct lu_env *env,
200                          struct lprocfs_stats *stats, int idx)
201 {
202         struct lu_time_data *ltd = lu_time_data_get(env);
203         long long diff;
204
205         --ltd->ltd_tos;
206         LASSERT(0 <= ltd->ltd_tos);
207         LASSERT(ltd->ltd_tos < ARRAY_SIZE(ltd->ltd_timestamp));
208         diff = lu_time_stamp_get() - ltd->ltd_timestamp[ltd->ltd_tos];
209         if (diff >= 0 && stats != NULL)
210                 lprocfs_counter_add(stats, idx, diff);
211 }
212 EXPORT_SYMBOL(lu_lprocfs_time_end);