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