Add stopwatch APIs for timing
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5c09b41..a1c9e42 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -55,8 +55,10 @@
 	IF(WIN32)
 		TARGET_LINK_LIBRARIES(${target} ws2_32)
 	ELSEIF(CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)")
-		TARGET_LINK_LIBRARIES(${target} socket nsl)
-	ENDIF ()
+		TARGET_LINK_LIBRARIES(${target} socket nsl rt)
+	ELSE()
+		TARGET_LINK_LIBRARIES(${target} rt)
+	ENDIF()
 	IF(THREADSAFE)
 		TARGET_LINK_LIBRARIES(${target} ${CMAKE_THREAD_LIBS_INIT})
 	ENDIF()
diff --git a/src/timing.c b/src/timing.c
new file mode 100644
index 0000000..cf729ea
--- /dev/null
+++ b/src/timing.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "common.h"
+#include "timing.h"
+
+#ifdef GIT_WIN32
+
+#define TICKS_PER_SECOND	1000
+
+int git_stopwatch_start(git_stopwatch *s)
+{
+	/* Try first to use the high-performance counter */
+	if (!QueryPerformanceFrequency(&s->freq) ||
+		!QueryPerformanceCounter(&s->start)) {
+		/* Fall back to GetTickCount */
+		s->freq.QuadPart = 0;
+		s->start.LowPart = GetTickCount();
+	}
+
+	s->running = 1;
+
+	return 0;
+}
+
+int git_stopwatch_query(double *out_elapsed_seconds, git_stopwatch *s)
+{
+	LARGE_INTEGER end;
+	double elapsed_seconds;
+
+	if (!s->running) {
+		giterr_set(GITERR_INVALID, "Stopwatch is not running");
+		return -1;
+	}
+
+	if (s->freq.QuadPart) {
+		if (!QueryPerformanceCounter(&end)) {
+			giterr_set(GITERR_OS, "Unable to read performance counter");
+			return -1;
+		}
+
+		elapsed_seconds = (end.QuadPart - s->start.QuadPart) / (double)s->freq.QuadPart;
+	} else {
+		DWORD end_ticks = GetTickCount();
+
+		/* Unsigned subtraction handles tick count wraparound */
+		elapsed_seconds = (end_ticks - s->start.LowPart) / (double)TICKS_PER_SECOND;
+	}
+
+	/* Just to be on the safe side */
+	if (elapsed_seconds < 0)
+		elapsed_seconds = 0;
+
+	*out_elapsed_seconds = elapsed_seconds;
+
+	return 0;
+}
+
+#elif __APPLE__
+
+int git_stopwatch_start(git_stopwatch *s)
+{
+	(void)mach_timebase_info(&s->info);
+	s->start = mach_absolute_time();
+
+	s->running = 1;
+
+	return 0;
+}
+
+int git_stopwatch_query(double *out_elapsed_seconds, git_stopwatch *s)
+{
+	uint64_t end;
+	double elapsed_seconds;
+
+	if (!s->running) {
+		giterr_set(GITERR_INVALID, "Stopwatch is not running");
+		return -1;
+	}
+
+	end = mach_absolute_time();
+	elapsed_seconds = 0;
+
+	if (end > start) {
+		elapsed_seconds = (double)s->info.numer * (end - start);
+		elapsed_seconds /= (double)s->info.denom * 1E9L;
+	}
+
+	*out_elapsed_seconds = elapsed_seconds;
+
+	return 0;
+}
+
+#else
+
+int git_stopwatch_start(git_stopwatch *s)
+{
+	if (clock_gettime(CLOCK_MONOTONIC, &s->start)) {
+		giterr_set(GITERR_OS, "Unable to get the monotonic timer");
+		return -1;
+	}
+
+	s->running = 1;
+
+	return 0;
+}
+
+int git_stopwatch_query(double *out_elapsed_seconds, git_stopwatch *s)
+{
+	struct timespec end, elapsed;
+	double elapsed_seconds;
+
+	if (!s->running) {
+		giterr_set(GITERR_INVALID, "Stopwatch is not running");
+		return -1;
+	}
+
+	if (clock_gettime(CLOCK_MONOTONIC, &end)) {
+		giterr_set(GITERR_OS, "Unable to get the monotonic timer");
+		return -1;
+	}
+
+	elapsed_seconds = 0;
+
+	/* If end < start, then we consider the elapsed time to be zero */
+	if (end.tv_sec > s->start.tv_sec ||
+		(end.tv_sec == s->start.tv_sec && end.tv_nsec > s->start.tv_nsec)) {
+		elapsed.tv_sec = end.tv_sec - s->start.tv_sec;
+		elapsed.tv_nsec = end.tv_nsec - s->start.tv_nsec;
+
+		if (elapsed.tv_nsec < 0) {
+			elapsed.tv_sec--;
+			elapsed.tv_nsec += 1E9L;
+		}
+
+		elapsed_seconds = (double)elapsed.tv_sec + elapsed.tv_nsec / (double)1E9;
+	}
+
+	*out_elapsed_seconds = elapsed_seconds;
+
+	return 0;
+}
+
+#endif
\ No newline at end of file
diff --git a/src/timing.h b/src/timing.h
new file mode 100644
index 0000000..6ee631a
--- /dev/null
+++ b/src/timing.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_timing_h__
+#define INCLUDE_timing_h__
+
+#include "common.h"
+
+#ifndef GIT_WIN32
+# include <time.h>
+#endif
+
+#ifdef __APPLE__
+# include <mach/mach_time.h>
+#endif
+
+#ifdef GIT_WIN32
+
+typedef struct git_stopwatch {
+	LARGE_INTEGER freq;
+	LARGE_INTEGER start;
+	unsigned running : 1;
+} git_stopwatch;
+
+#elif __APPLE__
+
+typedef struct git_stopwatch {
+	mach_timebase_info_data_t info;
+	uint64_t start;
+	unsigned running : 1;
+} git_stopwatch;
+
+#else
+
+typedef struct git_stopwatch {
+	struct timespec start;
+	unsigned running : 1;
+} git_stopwatch;
+
+#endif
+
+extern int git_stopwatch_start(git_stopwatch *s);
+extern int git_stopwatch_query(double *out_elapsed_seconds, git_stopwatch *s);
+
+#endif
diff --git a/tests-clar/online/clone.c b/tests-clar/online/clone.c
index dc5aa41..e4d79cc 100644
--- a/tests-clar/online/clone.c
+++ b/tests-clar/online/clone.c
@@ -5,6 +5,7 @@
 #include "remote.h"
 #include "fileops.h"
 #include "refs.h"
+#include "timing.h"
 
 #define LIVE_REPO_URL "http://github.com/libgit2/TestGitRepository"
 #define LIVE_EMPTYREPO_URL "http://github.com/libgit2/TestEmptyRepository"
@@ -39,7 +40,10 @@
 void test_online_clone__network_full(void)
 {
 	git_remote *origin;
+	git_stopwatch s;
+	double elapsed_seconds;
 
+	cl_git_pass(git_stopwatch_start(&s));
 	cl_git_pass(git_clone(&g_repo, LIVE_REPO_URL, "./foo", &g_options));
 	cl_assert(!git_repository_is_bare(g_repo));
 	cl_git_pass(git_remote_load(&origin, g_repo, "origin"));
@@ -47,6 +51,9 @@
 	cl_assert_equal_i(GIT_REMOTE_DOWNLOAD_TAGS_AUTO, origin->download_tags);
 
 	git_remote_free(origin);
+	
+	cl_git_pass(git_stopwatch_query(&elapsed_seconds, &s));
+	cl_assert(elapsed_seconds > 0);
 }
 
 void test_online_clone__network_bare(void)