diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp
index b3e6b6117d..22af011a46 100644
--- a/libraries/gpu/src/gpu/Batch.cpp
+++ b/libraries/gpu/src/gpu/Batch.cpp
@@ -245,3 +245,20 @@ void Batch::setFramebuffer(const FramebufferPointer& framebuffer) {
 
 }
 
+void Batch::beginQuery(const QueryPointer& query) {
+    ADD_COMMAND(beginQuery);
+
+    _params.push_back(_queries.cache(query));
+}
+
+void Batch::endQuery(const QueryPointer& query) {
+    ADD_COMMAND(endQuery);
+
+    _params.push_back(_queries.cache(query));
+}
+
+void Batch::getQuery(const QueryPointer& query) {
+    ADD_COMMAND(getQuery);
+
+    _params.push_back(_queries.cache(query));
+}
diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h
index 0cc1a6bee3..e4cadbb64d 100644
--- a/libraries/gpu/src/gpu/Batch.h
+++ b/libraries/gpu/src/gpu/Batch.h
@@ -18,6 +18,7 @@
 
 #include <vector>
 
+#include "Query.h"
 #include "Stream.h"
 #include "Texture.h"
 
@@ -108,6 +109,11 @@ public:
     // Framebuffer Stage
     void setFramebuffer(const FramebufferPointer& framebuffer);
 
+    // Query Section
+    void beginQuery(const QueryPointer& query);
+    void endQuery(const QueryPointer& query);
+    void getQuery(const QueryPointer& query);
+
     // TODO: As long as we have gl calls explicitely issued from interface
     // code, we need to be able to record and batch these calls. THe long 
     // term strategy is to get rid of any GL calls in favor of the HIFI GPU API
@@ -176,6 +182,10 @@ public:
 
         COMMAND_setFramebuffer,
 
+        COMMAND_beginQuery,
+        COMMAND_endQuery,
+        COMMAND_getQuery,
+
         // TODO: As long as we have gl calls explicitely issued from interface
         // code, we need to be able to record and batch these calls. THe long 
         // term strategy is to get rid of any GL calls in favor of the HIFI GPU API
@@ -279,6 +289,7 @@ public:
     typedef Cache<Transform>::Vector TransformCaches;
     typedef Cache<PipelinePointer>::Vector PipelineCaches;
     typedef Cache<FramebufferPointer>::Vector FramebufferCaches;
+    typedef Cache<QueryPointer>::Vector QueryCaches;
 
     // Cache Data in a byte array if too big to fit in Param
     // FOr example Mat4s are going there
@@ -303,6 +314,7 @@ public:
     TransformCaches _transforms;
     PipelineCaches _pipelines;
     FramebufferCaches _framebuffers;
+    QueryCaches _queries;
 
 protected:
 };
diff --git a/libraries/gpu/src/gpu/Context.h b/libraries/gpu/src/gpu/Context.h
index 2207575274..4eb0976e3c 100644
--- a/libraries/gpu/src/gpu/Context.h
+++ b/libraries/gpu/src/gpu/Context.h
@@ -99,6 +99,15 @@ public:
         return reinterpret_cast<T*>(framebuffer.getGPUObject());
     }
 
+    template< typename T >
+    static void setGPUObject(const Query& query, T* object) {
+        query.setGPUObject(object);
+    }
+    template< typename T >
+    static T* getGPUObject(const Query& query) {
+        return reinterpret_cast<T*>(query.getGPUObject());
+    }
+
 protected:
 
 };
diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp
index 54a54ce2a5..d493978b88 100644
--- a/libraries/gpu/src/gpu/GLBackend.cpp
+++ b/libraries/gpu/src/gpu/GLBackend.cpp
@@ -39,6 +39,9 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
 
     (&::gpu::GLBackend::do_setFramebuffer),
 
+    (&::gpu::GLBackend::do_beginQuery),
+    (&::gpu::GLBackend::do_endQuery),
+    (&::gpu::GLBackend::do_getQuery),
 
     (&::gpu::GLBackend::do_glEnable),
     (&::gpu::GLBackend::do_glDisable),
@@ -261,7 +264,6 @@ void GLBackend::do_clearFramebuffer(Batch& batch, uint32 paramOffset) {
     (void) CHECK_GL_ERROR();
 }
 
-
 // TODO: As long as we have gl calls explicitely issued from interface
 // code, we need to be able to record and batch these calls. THe long 
 // term strategy is to get rid of any GL calls in favor of the HIFI GPU API
diff --git a/libraries/gpu/src/gpu/GLBackend.h b/libraries/gpu/src/gpu/GLBackend.h
index 78b0f0838e..16e2ed62e3 100644
--- a/libraries/gpu/src/gpu/GLBackend.h
+++ b/libraries/gpu/src/gpu/GLBackend.h
@@ -189,6 +189,18 @@ public:
     static GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer);
     static GLuint getFramebufferID(const FramebufferPointer& framebuffer);
 
+    class GLQuery : public GPUObject {
+    public:
+        GLuint _qo = 0;
+        GLuint64 _result = 0;
+
+        GLQuery();
+        ~GLQuery();
+    };
+    static GLQuery* syncGPUObject(const Query& query);
+    static GLuint getQueryID(const QueryPointer& query);
+
+
     static const int MAX_NUM_ATTRIBUTES = Stream::NUM_INPUT_SLOTS;
     static const int MAX_NUM_INPUT_BUFFERS = 16;
 
@@ -369,6 +381,11 @@ protected:
         OutputStageState() {}
     } _output;
 
+    // Query section
+    void do_beginQuery(Batch& batch, uint32 paramOffset);
+    void do_endQuery(Batch& batch, uint32 paramOffset);
+    void do_getQuery(Batch& batch, uint32 paramOffset);
+
     // TODO: As long as we have gl calls explicitely issued from interface
     // code, we need to be able to record and batch these calls. THe long 
     // term strategy is to get rid of any GL calls in favor of the HIFI GPU API
diff --git a/libraries/gpu/src/gpu/GLBackendOutput.cpp b/libraries/gpu/src/gpu/GLBackendOutput.cpp
index 30b60ad183..1a7c5d2281 100755
--- a/libraries/gpu/src/gpu/GLBackendOutput.cpp
+++ b/libraries/gpu/src/gpu/GLBackendOutput.cpp
@@ -166,4 +166,3 @@ void GLBackend::do_setFramebuffer(Batch& batch, uint32 paramOffset) {
         _output._framebuffer = framebuffer;
     }
 }
-
diff --git a/libraries/gpu/src/gpu/GLBackendQuery.cpp b/libraries/gpu/src/gpu/GLBackendQuery.cpp
new file mode 100644
index 0000000000..39db19dafd
--- /dev/null
+++ b/libraries/gpu/src/gpu/GLBackendQuery.cpp
@@ -0,0 +1,106 @@
+//
+//  GLBackendQuery.cpp
+//  libraries/gpu/src/gpu
+//
+//  Created by Sam Gateau on 7/7/2015.
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+#include "GPULogging.h"
+#include "GLBackendShared.h"
+
+
+using namespace gpu;
+
+GLBackend::GLQuery::GLQuery() {}
+
+GLBackend::GLQuery::~GLQuery() {
+    if (_qo != 0) {
+        glDeleteQueries(1, &_qo);
+    }
+}
+
+GLBackend::GLQuery* GLBackend::syncGPUObject(const Query& query) {
+    GLQuery* object = Backend::getGPUObject<GLBackend::GLQuery>(query);
+
+    // If GPU object already created and in sync
+    if (object) {
+        return object;
+    }
+
+    // need to have a gpu object?
+    if (!object) {
+        GLuint qo;
+        glGenQueries(1, &qo);
+        (void) CHECK_GL_ERROR();
+        GLuint64 result = -1;
+
+        // All is green, assign the gpuobject to the Query
+        object = new GLQuery();
+        object->_qo = qo;
+        object->_result = result;
+        Backend::setGPUObject(query, object);
+    }
+
+    return object;
+}
+
+
+
+GLuint GLBackend::getQueryID(const QueryPointer& query) {
+    if (!query) {
+        return 0;
+    }
+    GLQuery* object = GLBackend::syncGPUObject(*query);
+    if (object) {
+        return object->_qo;
+    } else {
+        return 0;
+    }
+}
+
+void GLBackend::do_beginQuery(Batch& batch, uint32 paramOffset) {
+    auto query = batch._queries.get(batch._params[paramOffset]._uint);
+    GLQuery* glquery = syncGPUObject(*query);
+    if (glquery) {
+        #if (GPU_FEATURE_PROFILE == GPU_LEGACY)
+            // (EXT_TIMER_QUERY)
+            glBeginQuery(GL_TIME_ELAPSED_EXT, glquery->_qo);
+        #else
+            glBeginQuery(GL_TIME_ELAPSED, glquery->_qo);
+        #endif
+        (void)CHECK_GL_ERROR();
+    }
+}
+
+void GLBackend::do_endQuery(Batch& batch, uint32 paramOffset) {
+    auto query = batch._queries.get(batch._params[paramOffset]._uint);
+    GLQuery* glquery = syncGPUObject(*query);
+    if (glquery) {
+        #if (GPU_FEATURE_PROFILE == GPU_LEGACY)
+            // (EXT_TIMER_QUERY)
+            glEndQuery(GL_TIME_ELAPSED_EXT);
+        #else
+            glEndQuery(GL_TIME_ELAPSED);
+        #endif
+        (void)CHECK_GL_ERROR();
+    }
+}
+
+void GLBackend::do_getQuery(Batch& batch, uint32 paramOffset) {
+    auto query = batch._queries.get(batch._params[paramOffset]._uint);
+    GLQuery* glquery = syncGPUObject(*query);
+    if (glquery) { 
+        #if (GPU_FEATURE_PROFILE == GPU_LEGACY)
+            // (EXT_TIMER_QUERY)
+            #if !defined(Q_OS_LINUX)
+            glGetQueryObjectui64vEXT(glquery->_qo, GL_QUERY_RESULT, &glquery->_result);
+            #endif
+        #else
+            glGetQueryObjectui64v(glquery->_qo, GL_QUERY_RESULT, &glquery->_result);
+        #endif
+        (void)CHECK_GL_ERROR();
+    }
+}
diff --git a/libraries/gpu/src/gpu/Query.cpp b/libraries/gpu/src/gpu/Query.cpp
new file mode 100644
index 0000000000..b8ed729c99
--- /dev/null
+++ b/libraries/gpu/src/gpu/Query.cpp
@@ -0,0 +1,27 @@
+//
+//  Query.cpp
+//  interface/src/gpu
+//
+//  Created by Niraj Venkat on 7/7/2015.
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+#include "Query.h"
+
+#include <QDebug>
+
+using namespace gpu;
+
+Query::Query()
+{
+}
+
+Query::~Query()
+{
+}
+
+double Query::getElapsedTime() {
+    return 0.0;
+}
diff --git a/libraries/gpu/src/gpu/Query.h b/libraries/gpu/src/gpu/Query.h
new file mode 100644
index 0000000000..0a4d554e77
--- /dev/null
+++ b/libraries/gpu/src/gpu/Query.h
@@ -0,0 +1,45 @@
+//
+//  Query.h
+//  interface/src/gpu
+//
+//  Created by Niraj Venkat on 7/7/2015.
+//  Copyright 2015 High Fidelity, Inc.
+//
+//  Distributed under the Apache License, Version 2.0.
+//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
+//
+#ifndef hifi_gpu_Query_h
+#define hifi_gpu_Query_h
+
+#include <assert.h>
+#include <memory>
+#include <vector>
+#include "GPUConfig.h"
+
+#include "Format.h"
+
+namespace gpu {
+
+    class Query {
+    public:
+        Query();
+        ~Query();
+
+        uint32 queryResult;
+
+        double getElapsedTime();
+
+    protected:
+        
+        // This shouldn't be used by anything else than the Backend class with the proper casting.
+        mutable GPUObject* _gpuObject = NULL;
+        void setGPUObject(GPUObject* gpuObject) const { _gpuObject = gpuObject; }
+        GPUObject* getGPUObject() const { return _gpuObject; }
+        friend class Backend; 
+    };
+    
+    typedef std::shared_ptr<Query> QueryPointer;
+    typedef std::vector< QueryPointer > Queries;
+};
+
+#endif
diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp
index 8de5c8af01..55f4f72574 100755
--- a/libraries/render-utils/src/RenderDeferredTask.cpp
+++ b/libraries/render-utils/src/RenderDeferredTask.cpp
@@ -76,6 +76,12 @@ RenderDeferredTask::RenderDeferredTask() : Task() {
 
     _jobs.push_back(Job(new DrawOverlay3D::JobModel("DrawOverlay3D")));
     _jobs.push_back(Job(new ResetGLState::JobModel()));
+
+    // Give ourselves 3 frmaes of timer queries
+    _timerQueries.push_back(gpu::QueryPointer(new gpu::Query()));
+    _timerQueries.push_back(gpu::QueryPointer(new gpu::Query()));
+    _timerQueries.push_back(gpu::QueryPointer(new gpu::Query()));
+    _currentTimerQueryIndex = 0;
 }
 
 RenderDeferredTask::~RenderDeferredTask() {
@@ -102,6 +108,7 @@ void RenderDeferredTask::run(const SceneContextPointer& sceneContext, const Rend
     for (auto job : _jobs) {
         job.run(sceneContext, renderContext);
     }
+
 };
 
 void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) {
diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h
index 3d11e97634..4040606c62 100755
--- a/libraries/render-utils/src/RenderDeferredTask.h
+++ b/libraries/render-utils/src/RenderDeferredTask.h
@@ -77,6 +77,9 @@ public:
 
     virtual void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
 
+
+    gpu::Queries _timerQueries;
+    int _currentTimerQueryIndex = 0;
 };