mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	common: Add a generic interface for logging telemetry fields.
This commit is contained in:
		
							parent
							
								
									c291db72e7
								
							
						
					
					
						commit
						a4760e939f
					
				
					 3 changed files with 238 additions and 0 deletions
				
			
		|  | @ -38,6 +38,7 @@ set(SRCS | ||||||
|             param_package.cpp |             param_package.cpp | ||||||
|             scm_rev.cpp |             scm_rev.cpp | ||||||
|             string_util.cpp |             string_util.cpp | ||||||
|  |             telemetry.cpp | ||||||
|             thread.cpp |             thread.cpp | ||||||
|             timer.cpp |             timer.cpp | ||||||
|             ) |             ) | ||||||
|  | @ -74,6 +75,7 @@ set(HEADERS | ||||||
|             string_util.h |             string_util.h | ||||||
|             swap.h |             swap.h | ||||||
|             synchronized_wrapper.h |             synchronized_wrapper.h | ||||||
|  |             telemetry.h | ||||||
|             thread.h |             thread.h | ||||||
|             thread_queue_list.h |             thread_queue_list.h | ||||||
|             timer.h |             timer.h | ||||||
|  |  | ||||||
							
								
								
									
										40
									
								
								src/common/telemetry.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/common/telemetry.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,40 @@ | ||||||
|  | // Copyright 2017 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #include <algorithm> | ||||||
|  | #include "common/telemetry.h" | ||||||
|  | 
 | ||||||
|  | namespace Telemetry { | ||||||
|  | 
 | ||||||
|  | void FieldCollection::Accept(VisitorInterface& visitor) const { | ||||||
|  |     for (const auto& field : fields) { | ||||||
|  |         field.second->Accept(visitor); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void FieldCollection::AddField(std::unique_ptr<FieldInterface> field) { | ||||||
|  |     fields[field->GetName()] = std::move(field); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template <class T> | ||||||
|  | void Field<T>::Accept(VisitorInterface& visitor) const { | ||||||
|  |     visitor.Visit(*this); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template class Field<bool>; | ||||||
|  | template class Field<double>; | ||||||
|  | template class Field<float>; | ||||||
|  | template class Field<u8>; | ||||||
|  | template class Field<u16>; | ||||||
|  | template class Field<u32>; | ||||||
|  | template class Field<u64>; | ||||||
|  | template class Field<s8>; | ||||||
|  | template class Field<s16>; | ||||||
|  | template class Field<s32>; | ||||||
|  | template class Field<s64>; | ||||||
|  | template class Field<std::string>; | ||||||
|  | template class Field<const char*>; | ||||||
|  | template class Field<std::chrono::microseconds>; | ||||||
|  | 
 | ||||||
|  | } // namespace Telemetry
 | ||||||
							
								
								
									
										196
									
								
								src/common/telemetry.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								src/common/telemetry.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,196 @@ | ||||||
|  | // Copyright 2017 Citra Emulator Project
 | ||||||
|  | // Licensed under GPLv2 or any later version
 | ||||||
|  | // Refer to the license.txt file included.
 | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <chrono> | ||||||
|  | #include <map> | ||||||
|  | #include <memory> | ||||||
|  | #include <string> | ||||||
|  | #include "common/common_types.h" | ||||||
|  | 
 | ||||||
|  | namespace Telemetry { | ||||||
|  | 
 | ||||||
|  | /// Field type, used for grouping fields together in the final submitted telemetry log
 | ||||||
|  | enum class FieldType : u8 { | ||||||
|  |     None = 0,     ///< No specified field group
 | ||||||
|  |     App,          ///< Citra application fields (e.g. version, branch, etc.)
 | ||||||
|  |     Session,      ///< Emulated session fields (e.g. title ID, log, etc.)
 | ||||||
|  |     Performance,  ///< Emulated performance (e.g. fps, emulated CPU speed, etc.)
 | ||||||
|  |     UserFeedback, ///< User submitted feedback (e.g. star rating, user notes, etc.)
 | ||||||
|  |     UserConfig,   ///< User configuration fields (e.g. emulated CPU core, renderer, etc.)
 | ||||||
|  |     UserSystem,   ///< User system information (e.g. host CPU type, RAM, etc.)
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct VisitorInterface; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Interface class for telemetry data fields. | ||||||
|  |  */ | ||||||
|  | class FieldInterface : NonCopyable { | ||||||
|  | public: | ||||||
|  |     virtual ~FieldInterface() = default; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Accept method for the visitor pattern. | ||||||
|  |      * @param visitor Reference to the visitor that will visit this field. | ||||||
|  |      */ | ||||||
|  |     virtual void Accept(VisitorInterface& visitor) const = 0; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Gets the name of this field. | ||||||
|  |      * @returns Name of this field as a string. | ||||||
|  |      */ | ||||||
|  |     virtual const std::string& GetName() const = 0; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Represents a telemetry data field, i.e. a unit of data that gets logged and submitted to our | ||||||
|  |  * telemetry web service. | ||||||
|  |  */ | ||||||
|  | template <typename T> | ||||||
|  | class Field : public FieldInterface { | ||||||
|  | public: | ||||||
|  |     Field(FieldType type, std::string name, const T& value) | ||||||
|  |         : type(type), name(std::move(name)), value(value) {} | ||||||
|  | 
 | ||||||
|  |     Field(FieldType type, std::string name, T&& value) | ||||||
|  |         : type(type), name(std::move(name)), value(std::move(value)) {} | ||||||
|  | 
 | ||||||
|  |     Field(const Field& other) : Field(other.type, other.name, other.value) {} | ||||||
|  | 
 | ||||||
|  |     Field& operator=(const Field& other) { | ||||||
|  |         type = other.type; | ||||||
|  |         name = other.name; | ||||||
|  |         value = other.value; | ||||||
|  |         return *this; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Field& operator=(Field&& other) { | ||||||
|  |         type = other.type; | ||||||
|  |         name = std::move(other.name); | ||||||
|  |         value = std::move(other.value); | ||||||
|  |         return *this; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void Accept(VisitorInterface& visitor) const override; | ||||||
|  | 
 | ||||||
|  |     const std::string& GetName() const override { | ||||||
|  |         return name; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Returns the type of the field. | ||||||
|  |      */ | ||||||
|  |     FieldType GetType() const { | ||||||
|  |         return type; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Returns the value of the field. | ||||||
|  |      */ | ||||||
|  |     const T& GetValue() const { | ||||||
|  |         return value; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline bool operator==(const Field<T>& other) { | ||||||
|  |         return (type == other.type) && (name == other.name) && (value == other.value); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     inline bool operator!=(const Field<T>& other) { | ||||||
|  |         return !(*this == other); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     std::string name; ///< Field name, must be unique
 | ||||||
|  |     FieldType type{}; ///< Field type, used for grouping fields together
 | ||||||
|  |     T value;          ///< Field value
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Collection of data fields that have been logged. | ||||||
|  |  */ | ||||||
|  | class FieldCollection final : NonCopyable { | ||||||
|  | public: | ||||||
|  |     FieldCollection() = default; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Accept method for the visitor pattern, visits each field in the collection. | ||||||
|  |      * @param visitor Reference to the visitor that will visit each field. | ||||||
|  |      */ | ||||||
|  |     void Accept(VisitorInterface& visitor) const; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Creates a new field and adds it to the field collection. | ||||||
|  |      * @param type Type of the field to add. | ||||||
|  |      * @param name Name of the field to add. | ||||||
|  |      * @param value Value for the field to add. | ||||||
|  |      */ | ||||||
|  |     template <typename T> | ||||||
|  |     void AddField(FieldType type, const char* name, T value) { | ||||||
|  |         return AddField(std::make_unique<Field<T>>(type, name, std::move(value))); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Adds a new field to the field collection. | ||||||
|  |      * @param field Field to add to the field collection. | ||||||
|  |      */ | ||||||
|  |     void AddField(std::unique_ptr<FieldInterface> field); | ||||||
|  | 
 | ||||||
|  | private: | ||||||
|  |     std::map<std::string, std::unique_ptr<FieldInterface>> fields; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Telemetry fields visitor interface class. A backend to log to a web service should implement | ||||||
|  |  * this interface. | ||||||
|  |  */ | ||||||
|  | struct VisitorInterface : NonCopyable { | ||||||
|  |     virtual ~VisitorInterface() = default; | ||||||
|  | 
 | ||||||
|  |     virtual void Visit(const Field<bool>& field) = 0; | ||||||
|  |     virtual void Visit(const Field<double>& field) = 0; | ||||||
|  |     virtual void Visit(const Field<float>& field) = 0; | ||||||
|  |     virtual void Visit(const Field<u8>& field) = 0; | ||||||
|  |     virtual void Visit(const Field<u16>& field) = 0; | ||||||
|  |     virtual void Visit(const Field<u32>& field) = 0; | ||||||
|  |     virtual void Visit(const Field<u64>& field) = 0; | ||||||
|  |     virtual void Visit(const Field<s8>& field) = 0; | ||||||
|  |     virtual void Visit(const Field<s16>& field) = 0; | ||||||
|  |     virtual void Visit(const Field<s32>& field) = 0; | ||||||
|  |     virtual void Visit(const Field<s64>& field) = 0; | ||||||
|  |     virtual void Visit(const Field<std::string>& field) = 0; | ||||||
|  |     virtual void Visit(const Field<const char*>& field) = 0; | ||||||
|  |     virtual void Visit(const Field<std::chrono::microseconds>& field) = 0; | ||||||
|  | 
 | ||||||
|  |     /// Completion method, called once all fields have been visited
 | ||||||
|  |     virtual void Complete() = 0; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | /**
 | ||||||
|  |  * Empty implementation of VisitorInterface that drops all fields. Used when a functional | ||||||
|  |  * backend implementation is not available. | ||||||
|  |  */ | ||||||
|  | struct NullVisitor : public VisitorInterface { | ||||||
|  |     ~NullVisitor() = default; | ||||||
|  | 
 | ||||||
|  |     void Visit(const Field<bool>& /*field*/) override {} | ||||||
|  |     void Visit(const Field<double>& /*field*/) override {} | ||||||
|  |     void Visit(const Field<float>& /*field*/) override {} | ||||||
|  |     void Visit(const Field<u8>& /*field*/) override {} | ||||||
|  |     void Visit(const Field<u16>& /*field*/) override {} | ||||||
|  |     void Visit(const Field<u32>& /*field*/) override {} | ||||||
|  |     void Visit(const Field<u64>& /*field*/) override {} | ||||||
|  |     void Visit(const Field<s8>& /*field*/) override {} | ||||||
|  |     void Visit(const Field<s16>& /*field*/) override {} | ||||||
|  |     void Visit(const Field<s32>& /*field*/) override {} | ||||||
|  |     void Visit(const Field<s64>& /*field*/) override {} | ||||||
|  |     void Visit(const Field<std::string>& /*field*/) override {} | ||||||
|  |     void Visit(const Field<const char*>& /*field*/) override {} | ||||||
|  |     void Visit(const Field<std::chrono::microseconds>& /*field*/) override {} | ||||||
|  | 
 | ||||||
|  |     void Complete() override {} | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace Telemetry
 | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue