{"id":576,"date":"2021-03-12T02:38:41","date_gmt":"2021-03-12T05:38:41","guid":{"rendered":"https:\/\/millerdantas.com\/blog\/?p=576"},"modified":"2021-03-30T23:42:24","modified_gmt":"2021-03-31T02:42:24","slug":"otimizando-o-kmm-parte-1","status":"publish","type":"post","link":"https:\/\/millerdantas.com\/blog\/2021\/03\/12\/otimizando-o-kmm-parte-1\/","title":{"rendered":"Otimizando o KMM &#8211; Parte 1"},"content":{"rendered":"<h2>Onde paramos mesmo?<\/h2>\n<p>Em nosso \u00faltimo Snapshot tivemos esse resultado<\/p>\n<pre><code class=\"language-Csharp line-numbers\">Gen 0: 187\nGen 1: 72 \nGen 3: 11 \nTempo: 13179ms \nMem\u00f3ria: 590mb \n<\/code><\/pre>\n<p>Meu objetivo agora era parar de ficar perdendo tempo re-processando todos os mods, n\u00e3o fazia sentido.<\/p>\n<p>H\u00e1 v\u00e1rias solu\u00e7\u00f5es que podemos aplicar, a mais simples &#8220;pra mim&#8221;, seria utilizar um Helper que fiz pra <a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/github.com\/millerscout\/MMDHelpers.CSharp\/tree\/master\/MMDHelpers.CSharp.LocalData\">SqlLite <\/a> sendo assim eu iria facilitar e muito a quantidade de c\u00f3digo que eu escreveria.<\/p>\n<h2>Primeiro problema<\/h2>\n<p><\/p>\n<p>Fui percebendo que estava fazendo uma itera\u00e7\u00e3o desnecess\u00e1ria, pois eu j\u00e1 estava carregando os dados do Mod na mem\u00f3ria, depois de terminar de ler tudo eu iterava de novo s\u00f3 pra identificar as modifica\u00e7\u00f5es&#8230; mas isso \u00e9 redundante e o resultado era apenas ter o valor &#8220;Old&#8221;.<\/p>\n<p>Por\u00e9m como os mods podem ser re-ordenados o &#8220;Old&#8221; se mudar\u00e1 conforme o contexto, logo&#8230; \u00e9 uma informa\u00e7\u00e3o in\u00fatil.<\/p>\n<p>Resultado: Remo\u00e7\u00e3o desses c\u00f3digo in\u00fateis.<\/p>\n<h2>Segundo problema<\/h2>\n<p>Eu estava usando minha Library ent\u00e3o, o passo mais simples seria abrir uma connection com o banco e ir salvando no DB, algo como:<\/p>\n<pre><code class=\"language-CSharp line-numbers\">    var db  = new DataService();\n    db.Insert(query, parametros);\n<\/code><\/pre>\n<p>sim&#8230; \u00e9 s\u00f3 isso<\/p>\n<p>o \u00fanico problema \u00e9 que n\u00e3o estou inserindo 10 itens, e sim mais de 500K, ent\u00e3o meio que ele ficou processando por mais de 1 hora e n\u00e3o havia terminado <del>(eu dei uma pausa pra descansar, ele ficou processando enquanto isso)<\/del> logo precisava efetuar otimiza\u00e7\u00f5es&#8230; <del>(que novidade :x)<\/del><\/p>\n<pre><code>Mas eu j\u00e1 esperava isso, eu havia encontrado uma forma eficiente em SqlLite que itera e insere os dados, um dia eu posto mais detalhes (talvez)\n<\/code><\/pre>\n<p>o c\u00f3digo no final ficou:<\/p>\n<pre><code class=\"language-CSharp line-numbers\">        static Dictionary<string, object>[] List = new Dictionary<string, object>[5000];\n        static int lastIndex = 0;\n        public static void AddToList(int id, ItemType type, string key, string name, string empty, string flag2, State state)\n        {\n\n            List[lastIndex] = new Dictionary<string, object>(7)\n            {   { \"ModId\", id },\n                {\"Type\" , type },\n                {\"Section\" , key },\n                {\"Key\" , name },\n                {\"OldVal\" , string.Empty },\n                {\"NewVal\" , flag2 },\n                {\"State\" , state },\n            };\n            lastIndex++;\n            if (lastIndex > 5000)\n            {\n                var db = new DataService();\n\n                   db.InsertBatch(@\"INSERT INTO ModChange (\n                                            ModId,\n                                            Type,\n                                            Section,\n                                            [Key],\n                                            OldVal,\n                                            NewVal,\n                                            State\n                                        )\n                                        VALUES (\n                                            :ModId,\n                                            :Type,\n                                            :Section,\n                                            :Key,\n                                            :OldVal,\n                                            :NewVal,\n                                            :State\n                                        )\", List.Take(lastIndex));\n            List = new Dictionary<string, object>[5000];\n            lastIndex = 0;\n\n\n            }\n        }\n<\/code><\/pre>\n<pre><code>Bom um pouquinho grande, mas d\u00e1 pra entender, eu coloquei cada batch pra 5k de registro, me parecia ser suficiente, mas vamos ver como ficou o resultado no GC?\n<\/code><\/pre>\n<p><a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/millerdantas.com\/blog\/wp-content\/uploads\/2021\/03\/wp_editor_md_33093588a476d1327ba0480a9458684f.jpg\"><img decoding=\"async\" src=\"https:\/\/millerdantas.com\/blog\/wp-content\/uploads\/2021\/03\/wp_editor_md_33093588a476d1327ba0480a9458684f.jpg\" alt=\"\" \/><\/a><br \/>\n\u00c9&#8230; mais uma vez aumentamos a quantidade de varreduras do GC, mas o que podemos fazer pra resolver isso?<\/p>\n<p>N\u00f3s estamos criando uma lista de dictionary, que depois ser\u00e1 criado transformado em uma lista de parameters conforme o <a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/github.com\/millerscout\/MMDHelpers.CSharp\/blob\/master\/MMDHelpers.CSharp.LocalData\/SQLiteService.cs#L77\">c\u00f3digo aqui<\/a><\/p>\n<p>vamos resolver isso criando uma lista de parameters.<\/p>\n<pre><code class=\"language-CSharp line-numbers\">  static SQLiteParameter[][] List = new SQLiteParameter[12000][];\n        static int lastIndex = 0;\n        public static void AddToList(int id, ItemType type, string key, string name, string empty, string flag2, State state)\n        {\n            if (lastIndex == 12000)\n            {\n                UpdateDatabase();\n            }\n\n\n            List[lastIndex] = new SQLiteParameter[7] {\n                new SQLiteParameter(\"ModId\", id),\n                    new SQLiteParameter(\"Type\", type),\n                    new SQLiteParameter(\"Section\", key),\n                    new SQLiteParameter(\"Key\", name),\n                    new SQLiteParameter(\"OldVal\", empty),\n                    new SQLiteParameter(\"NewVal\", flag2),\n                    new SQLiteParameter(\"State\", state)\n            };\n\n            lastIndex++;\n\n\n\n        }\n\n        public static void UpdateDatabase()\n        {\n            var db = new DataService();\n            var query = @\"(..query..)\";\n\n            using (var connection = new SQLiteConnection($\"Data Source={DataService.DbLocation}; Version=3;\"))\n            {\n                connection.Open();\n                using (var transaction = connection.BeginTransaction())\n                using (var command = connection.CreateCommand())\n                {\n                    command.Prepare();\n                    command.CommandText = query;\n\n                    foreach (var item in List.Take(lastIndex))\n                    {\n                        command.Parameters.AddRange(item);\n                        command.ExecuteNonQuery();\n                    }\n\n                    transaction.Commit();\n                }\n            }\n\n            lastIndex = 0;\n        }\n<\/code><\/pre>\n<p>resultado:<br \/>\n<a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/millerdantas.com\/blog\/wp-content\/uploads\/2021\/03\/wp_editor_md_b76b013910a5d3c0de3dfc2ede1468c3.jpg\"><img decoding=\"async\" src=\"https:\/\/millerdantas.com\/blog\/wp-content\/uploads\/2021\/03\/wp_editor_md_b76b013910a5d3c0de3dfc2ede1468c3.jpg\" alt=\"\" \/><\/a><\/p>\n<p>o resultado pra mim \u00e9 simb\u00f3licamente o mesmo, mas por que ser\u00e1 que n\u00e3o houve melhora?<\/p>\n<p>existem duas coisas que pioram a vida:<br \/>\n&#8211; GC sendo executado com frequ\u00eancia porque tem objeto que n\u00e3o est\u00e1 sendo usado.<br \/>\n&#8211; Alocar algo na mem\u00f3ria tem seu custo..<\/p>\n<p>mas e se n\u00e3o criarmos mais objetos que precisamos usar?<\/p>\n<p>bom, fiz a adequa\u00e7\u00e3o no c\u00f3digo<\/p>\n<pre><code class=\"language-CSharp line-numbers\">static SQLiteParameter[][] List = new SQLiteParameter[5000][];\n        static int lastIndex = 0;\n        public static void AddToList(int id, ItemType type, string key, string name, string empty, string flag2, State state)\n        {\n            if (lastIndex == 5000)\n            {\n                UpdateDatabase();\n            }\n\n\n            if (List[lastIndex] == null)\n            {\n                List[lastIndex] = new SQLiteParameter[7] {\n                new SQLiteParameter(\"ModId\", id),\n                    new SQLiteParameter(\"Type\", type),\n                    new SQLiteParameter(\"Section\", key),\n                    new SQLiteParameter(\"Key\", name),\n                    new SQLiteParameter(\"OldVal\", empty),\n                    new SQLiteParameter(\"NewVal\", flag2),\n                    new SQLiteParameter(\"State\", state)\n                };\n            }\n            else\n            {\n                List[lastIndex][0].Value = id;\n                List[lastIndex][1].Value = type;\n                List[lastIndex][2].Value = key;\n                List[lastIndex][3].Value = name;\n                List[lastIndex][4].Value = empty;\n                List[lastIndex][5].Value = flag2;\n                List[lastIndex][6].Value = state;\n            }\n\n            lastIndex++;\n\n\n\n        }\n\n        public static void UpdateDatabase()\n        {\n            var db = new DataService();\n            var query = @\"INSERT INTO ModChange (\n                                            ModId,\n                                            Type,\n                                            Section,\n                                            [Key],\n                                            OldVal,\n                                            NewVal,\n                                            State\n                                        )\n                                        VALUES (\n                                            :ModId,\n                                            :Type,\n                                            :Section,\n                                            :Key,\n                                            :OldVal,\n                                            :NewVal,\n                                            :State\n                                        )\";\n\n            using (var connection = new SQLiteConnection($\"Data Source={DataService.DbLocation}; Version=3;\"))\n            {\n                connection.Open();\n                using (var transaction = connection.BeginTransaction())\n                using (var command = connection.CreateCommand())\n                {\n                    command.Prepare();\n                    command.CommandText = query;\n\n                    foreach (var item in List.Take(lastIndex))\n                    {\n                        command.Parameters.AddRange(item);\n                        command.ExecuteNonQuery();\n                    }\n\n                    transaction.Commit();\n                }\n            }\n\n            lastIndex = 0;\n        }\n<\/code><\/pre>\n<p>resultado:<br \/>\n<a class=\"wp-editor-md-post-content-link\" href=\"https:\/\/millerdantas.com\/blog\/wp-content\/uploads\/2021\/03\/wp_editor_md_27f3c57dcad3654fe06d0898218731e9.jpg\"><img decoding=\"async\" src=\"https:\/\/millerdantas.com\/blog\/wp-content\/uploads\/2021\/03\/wp_editor_md_27f3c57dcad3654fe06d0898218731e9.jpg\" alt=\"\" \/><\/a><\/p>\n<p>Vou encerrar por aqui,<br \/>\nmas para nossa TODO list temos:<br \/>\n&#8211; Processar somente os arquivos novos.<br \/>\n&#8211; implementar o carregamento de conflitos no frontend on-demand<br \/>\n&#8211; remover mais campos que n\u00e3o usamos pra ter mais efici\u00eancia.<br \/>\n&#8211; revalidar partes do c\u00f3digo que s\u00f3 s\u00e3o sujeira.<\/p>\n<p>Bom \u00e9 isso, at\u00e9 o pr\u00f3ximo post<\/p>\n<p>Esteja curioso!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Onde paramos mesmo? Em nosso \u00faltimo Snapshot tivemos esse resultado Gen 0: 187 Gen 1: 72 Gen 3: 11 Tempo: 13179ms Mem\u00f3ria: 590mb Meu objetivo agora era parar de ficar perdendo tempo re-processando todos os mods, n\u00e3o fazia sentido. H\u00e1 v\u00e1rias solu\u00e7\u00f5es que podemos aplicar, a mais simples &#8220;pra mim&#8221;, seria utilizar um Helper que &hellip; <a href=\"https:\/\/millerdantas.com\/blog\/2021\/03\/12\/otimizando-o-kmm-parte-1\/\" class=\"more-link\">Continue lendo <span class=\"screen-reader-text\">Otimizando o KMM &#8211; Parte 1<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-576","post","type-post","status-publish","format-standard","hentry","category-programacao"],"_links":{"self":[{"href":"https:\/\/millerdantas.com\/blog\/wp-json\/wp\/v2\/posts\/576","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/millerdantas.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/millerdantas.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/millerdantas.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/millerdantas.com\/blog\/wp-json\/wp\/v2\/comments?post=576"}],"version-history":[{"count":8,"href":"https:\/\/millerdantas.com\/blog\/wp-json\/wp\/v2\/posts\/576\/revisions"}],"predecessor-version":[{"id":596,"href":"https:\/\/millerdantas.com\/blog\/wp-json\/wp\/v2\/posts\/576\/revisions\/596"}],"wp:attachment":[{"href":"https:\/\/millerdantas.com\/blog\/wp-json\/wp\/v2\/media?parent=576"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/millerdantas.com\/blog\/wp-json\/wp\/v2\/categories?post=576"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/millerdantas.com\/blog\/wp-json\/wp\/v2\/tags?post=576"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}